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:
Torsten Grote
2018-04-26 16:17:38 -03:00
parent 0e04044ebb
commit bd5504de26
22 changed files with 614 additions and 417 deletions

View File

@@ -26,4 +26,7 @@ public interface IntroductionConstants {
String LABEL_AUTH_NONCE = "org.briarproject.briar.introduction/AUTH_NONCE"; String LABEL_AUTH_NONCE = "org.briarproject.briar.introduction/AUTH_NONCE";
String LABEL_ACTIVATE_MAC =
"org.briarproject.briar.introduction/ACTIVATE_MAC";
} }

View File

@@ -110,11 +110,11 @@ abstract class AbstractProtocolEngine<S extends Session>
return m; return m;
} }
Message sendActivateMessage(Transaction txn, PeerSession s, long timestamp) Message sendActivateMessage(Transaction txn, PeerSession s, long timestamp,
throws DbException { byte[] mac) throws DbException {
Message m = messageEncoder Message m = messageEncoder
.encodeActivateMessage(s.getContactGroupId(), timestamp, .encodeActivateMessage(s.getContactGroupId(), timestamp,
s.getLastLocalMessageId(), s.getSessionId()); s.getLastLocalMessageId(), s.getSessionId(), mac);
sendMessage(txn, ACTIVATE, s.getSessionId(), m, false); sendMessage(txn, ACTIVATE, s.getSessionId(), m, false);
return m; return m;
} }

View File

@@ -12,15 +12,22 @@ import javax.annotation.concurrent.Immutable;
class ActivateMessage extends AbstractIntroductionMessage { class ActivateMessage extends AbstractIntroductionMessage {
private final SessionId sessionId; private final SessionId sessionId;
private final byte[] mac;
protected ActivateMessage(MessageId messageId, GroupId groupId, 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); super(messageId, groupId, timestamp, previousMessageId);
this.sessionId = sessionId; this.sessionId = sessionId;
this.mac = mac;
} }
public SessionId getSessionId() { public SessionId getSessionId() {
return sessionId; return sessionId;
} }
public byte[] getMac() {
return mac;
}
} }

View File

@@ -4,7 +4,6 @@ import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.client.ContactGroupFactory;
import org.briarproject.bramble.api.contact.Contact; 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.contact.ContactManager;
import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey; 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.DatabaseComponent;
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.identity.Author;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -354,7 +352,7 @@ class IntroduceeProtocolEngine
IntroductionResponse request = IntroductionResponse request =
new IntroductionResponse(s.getSessionId(), m.getMessageId(), new IntroductionResponse(s.getSessionId(), m.getMessageId(),
m.getGroupId(), INTRODUCEE, m.getTimestamp(), false, m.getGroupId(), INTRODUCEE, m.getTimestamp(), false,
false, false, false, s.getRemoteAuthor().getName(), false, false, false, s.getRemote().author.getName(),
false); false);
IntroductionResponseReceivedEvent e = IntroductionResponseReceivedEvent e =
new IntroductionResponseReceivedEvent(c.getId(), request); new IntroductionResponseReceivedEvent(c.getId(), request);
@@ -383,16 +381,18 @@ class IntroduceeProtocolEngine
private IntroduceeSession onLocalAuth(Transaction txn, IntroduceeSession s) private IntroduceeSession onLocalAuth(Transaction txn, IntroduceeSession s)
throws DbException { throws DbException {
boolean alice = isAlice(txn, s);
byte[] mac; byte[] mac;
byte[] signature; byte[] signature;
SecretKey masterKey; SecretKey masterKey, aliceMacKey, bobMacKey;
try { try {
masterKey = crypto.deriveMasterKey(s, alice); masterKey = crypto.deriveMasterKey(s);
SecretKey macKey = crypto.deriveMacKey(masterKey, alice); aliceMacKey = crypto.deriveMacKey(masterKey, true);
bobMacKey = crypto.deriveMacKey(masterKey, false);
SecretKey ourMacKey = s.getLocal().alice ? aliceMacKey : bobMacKey;
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
mac = crypto.mac(macKey, s, localAuthor.getId(), alice); mac = crypto.authMac(ourMacKey, s, localAuthor.getId(),
signature = crypto.sign(macKey, localAuthor.getPrivateKey()); s.getLocal().alice);
signature = crypto.sign(ourMacKey, localAuthor.getPrivateKey());
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
// TODO // TODO
return abort(txn, s); return abort(txn, s);
@@ -400,7 +400,8 @@ class IntroduceeProtocolEngine
if (s.getState() != AWAIT_AUTH) throw new AssertionError(); if (s.getState() != AWAIT_AUTH) throw new AssertionError();
Message sent = sendAuthMessage(txn, s, getLocalTimestamp(s), mac, Message sent = sendAuthMessage(txn, s, getLocalTimestamp(s), mac,
signature); signature);
return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, masterKey, sent); return IntroduceeSession.addLocalAuth(s, AWAIT_AUTH, sent, masterKey,
aliceMacKey, bobMacKey);
} }
private IntroduceeSession onRemoteAuth(Transaction txn, private IntroduceeSession onRemoteAuth(Transaction txn,
@@ -411,33 +412,50 @@ class IntroduceeProtocolEngine
LocalAuthor localAuthor = identityManager.getLocalAuthor(txn); LocalAuthor localAuthor = identityManager.getLocalAuthor(txn);
try { try {
crypto.verifyMac(m.getMac(), s, localAuthor.getId()); crypto.verifyAuthMac(m.getMac(), s, localAuthor.getId());
crypto.verifySignature(m.getSignature(), s, localAuthor.getId()); crypto.verifySignature(m.getSignature(), s, localAuthor.getId());
} catch (GeneralSecurityException e) { } catch (GeneralSecurityException e) {
return abort(txn, s); return abort(txn, s);
} }
long timestamp = long timestamp = Math.min(s.getLocal().acceptTimestamp,
Math.min(s.getAcceptTimestamp(), s.getRemoteAcceptTimestamp()); s.getRemote().acceptTimestamp);
if (timestamp == -1) throw new AssertionError(); if (timestamp == -1) throw new AssertionError();
Map<TransportId, KeySetId> keys = null; boolean contactAdded = false;
try { try {
ContactId c = contactManager contactManager
.addContact(txn, s.getRemoteAuthor(), localAuthor.getId(), .addContact(txn, s.getRemote().author, localAuthor.getId(),
false, false); false, true);
if (s.getRemoteTransportProperties() == null || contactAdded = true;
s.getMasterKey() == null) throw new AssertionError();
transportPropertyManager.addRemoteProperties(txn, c,
s.getRemoteTransportProperties());
keys = keyManager
.addUnboundKeys(txn, new SecretKey(s.getMasterKey()),
timestamp, isAlice(txn, s));
} catch (ContactExistsException e) { } catch (ContactExistsException e) {
// Ignore this and continue without adding transport properties // Ignore this, because the other introducee might have deleted us.
// or unbound transport keys. Continue with keys as null. // 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 // Move to AWAIT_ACTIVATE state and clear key material from session
return IntroduceeSession.awaitActivate(s, m, sent, keys); return IntroduceeSession.awaitActivate(s, m, sent, keys);
@@ -449,23 +467,17 @@ class IntroduceeProtocolEngine
if (isInvalidDependency(s, m.getPreviousMessageId())) if (isInvalidDependency(s, m.getPreviousMessageId()))
return abort(txn, s); return abort(txn, s);
// Only bind keys if contact did not exist during AUTH // Validate MAC
if (s.getTransportKeys() != null) { try {
Contact c = crypto.verifyActivateMac(m.getMac(), s);
contactManager.getContact(txn, s.getRemoteAuthor().getId(), } catch (GeneralSecurityException e) {
identityManager.getLocalAuthor(txn).getId()); // TODO remove transport keys?
keyManager.bindKeys(txn, c.getId(), s.getTransportKeys()); return abort(txn, s);
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);
} }
// Activate transport keys
keyManager.activateKeys(txn, s.getTransportKeys());
// Move back to START state // Move back to START state
return IntroduceeSession return IntroduceeSession
.clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(), .clear(s, s.getLastLocalMessageId(), s.getLocalTimestamp(),
@@ -513,12 +525,6 @@ class IntroduceeProtocolEngine
s.getRequestTimestamp()); 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) private void addSessionId(Transaction txn, MessageId m, SessionId sessionId)
throws DbException { throws DbException {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();

View File

@@ -27,68 +27,44 @@ class IntroduceeSession extends Session<IntroduceeState>
implements PeerSession { implements PeerSession {
private final GroupId contactGroupId; private final GroupId contactGroupId;
private final long localTimestamp, acceptTimestamp, remoteAcceptTimestamp; private final Author introducer;
private final Local local;
private final Remote remote;
@Nullable @Nullable
private final MessageId lastLocalMessageId, lastRemoteMessageId; private final byte[] masterKey;
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;
@Nullable @Nullable
private final Map<TransportId, KeySetId> transportKeys; private final Map<TransportId, KeySetId> transportKeys;
IntroduceeSession(SessionId sessionId, IntroduceeState state, IntroduceeSession(SessionId sessionId, IntroduceeState state,
long requestTimestamp, GroupId contactGroupId, long requestTimestamp, GroupId contactGroupId, Author introducer,
@Nullable MessageId lastLocalMessageId, long localTimestamp, Local local, Remote remote, @Nullable byte[] masterKey,
@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,
@Nullable Map<TransportId, KeySetId> transportKeys) { @Nullable Map<TransportId, KeySetId> transportKeys) {
super(sessionId, state, requestTimestamp); super(sessionId, state, requestTimestamp);
this.contactGroupId = contactGroupId; this.contactGroupId = contactGroupId;
this.lastLocalMessageId = lastLocalMessageId;
this.localTimestamp = localTimestamp;
this.lastRemoteMessageId = lastRemoteMessageId;
this.introducer = introducer; this.introducer = introducer;
this.ephemeralPublicKey = ephemeralPublicKey; this.local = local;
this.ephemeralPrivateKey = ephemeralPrivateKey; this.remote = remote;
this.transportProperties = transportProperties;
this.acceptTimestamp = acceptTimestamp;
this.masterKey = masterKey; this.masterKey = masterKey;
this.remoteAuthor = remoteAuthor;
this.remoteEphemeralPublicKey = remoteEphemeralPublicKey;
this.remoteTransportProperties = remoteTransportProperties;
this.remoteAcceptTimestamp = remoteAcceptTimestamp;
this.transportKeys = transportKeys; this.transportKeys = transportKeys;
} }
static IntroduceeSession getInitial(GroupId contactGroupId, static IntroduceeSession getInitial(GroupId contactGroupId,
SessionId sessionId, Author introducer, Author remoteAuthor) { SessionId sessionId, Author introducer, boolean localIsAlice,
return new IntroduceeSession(sessionId, START, -1, contactGroupId, null, Author remoteAuthor) {
-1, null, introducer, null, null, null, -1, null, remoteAuthor, Local local =
null, null, -1, null); 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, static IntroduceeSession addRemoteRequest(IntroduceeSession s,
IntroduceeState state, RequestMessage m) { IntroduceeState state, RequestMessage m) {
Remote remote = new Remote(s.remote, m.getMessageId());
return new IntroduceeSession(s.getSessionId(), state, m.getTimestamp(), return new IntroduceeSession(s.getSessionId(), state, m.getTimestamp(),
s.contactGroupId, s.lastLocalMessageId, s.localTimestamp, s.contactGroupId, s.introducer, s.local, remote, s.masterKey,
m.getMessageId(), s.introducer, s.ephemeralPublicKey,
s.ephemeralPrivateKey, s.transportProperties, s.acceptTimestamp,
s.masterKey, s.remoteAuthor, s.remoteEphemeralPublicKey,
s.remoteTransportProperties, s.remoteAcceptTimestamp,
s.transportKeys); s.transportKeys);
} }
@@ -97,57 +73,66 @@ class IntroduceeSession extends Session<IntroduceeState>
byte[] ephemeralPublicKey, byte[] ephemeralPrivateKey, byte[] ephemeralPublicKey, byte[] ephemeralPrivateKey,
long acceptTimestamp, long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties) { 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, return new IntroduceeSession(s.getSessionId(), state,
s.getRequestTimestamp(), s.contactGroupId, s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
acceptMessage.getId(), acceptMessage.getTimestamp(), s.remote, s.masterKey, s.transportKeys);
s.lastRemoteMessageId, s.introducer, ephemeralPublicKey,
ephemeralPrivateKey, transportProperties,
acceptTimestamp, s.masterKey, s.remoteAuthor,
s.remoteEphemeralPublicKey, s.remoteTransportProperties,
s.remoteAcceptTimestamp, s.transportKeys);
} }
static IntroduceeSession addRemoteAccept(IntroduceeSession s, 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, return new IntroduceeSession(s.getSessionId(), state,
s.getRequestTimestamp(), s.contactGroupId, s.lastLocalMessageId, s.getRequestTimestamp(), s.contactGroupId, s.introducer,
s.localTimestamp, acceptMessage.getMessageId(), s.introducer, s.local, remote, s.masterKey, s.transportKeys);
s.ephemeralPublicKey, s.ephemeralPrivateKey,
s.transportProperties, s.acceptTimestamp, s.masterKey,
s.remoteAuthor, acceptMessage.getEphemeralPublicKey(),
acceptMessage.getTransportProperties(),
acceptMessage.getAcceptTimestamp(), s.transportKeys);
} }
static IntroduceeSession addLocalAuth(IntroduceeSession s, 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, return new IntroduceeSession(s.getSessionId(), state,
s.getRequestTimestamp(), s.contactGroupId, m.getId(), s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
m.getTimestamp(), s.lastRemoteMessageId, s.introducer, remote, masterKey.getBytes(), s.transportKeys);
s.ephemeralPublicKey, s.ephemeralPrivateKey,
s.transportProperties, s.acceptTimestamp, masterKey.getBytes(),
s.remoteAuthor, s.remoteEphemeralPublicKey,
s.remoteTransportProperties, s.remoteAcceptTimestamp,
s.transportKeys);
} }
static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m, static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m,
Message sent, @Nullable Map<TransportId, KeySetId> transportKeys) { 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, return new IntroduceeSession(s.getSessionId(), AWAIT_ACTIVATE,
s.getRequestTimestamp(), s.contactGroupId, sent.getId(), s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
sent.getTimestamp(), m.getMessageId(), s.introducer, null, null, remote, null, transportKeys);
null, s.acceptTimestamp, null, s.getRemoteAuthor(), null, null,
s.remoteAcceptTimestamp, transportKeys);
} }
static IntroduceeSession clear(IntroduceeSession s, static IntroduceeSession clear(IntroduceeSession s,
@Nullable MessageId lastLocalMessageId, long localTimestamp, @Nullable MessageId lastLocalMessageId, long localTimestamp,
@Nullable MessageId lastRemoteMessageId) { @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, return new IntroduceeSession(s.getSessionId(), START,
s.getRequestTimestamp(), s.getContactGroupId(), s.getRequestTimestamp(), s.contactGroupId, s.introducer, local,
lastLocalMessageId, localTimestamp, lastRemoteMessageId, remote, null, null);
s.getIntroducer(), null, null, null, -1, null,
s.getRemoteAuthor(), null, null, -1, null);
} }
@Override @Override
@@ -155,45 +140,38 @@ class IntroduceeSession extends Session<IntroduceeState>
return INTRODUCEE; return INTRODUCEE;
} }
@Override
public GroupId getContactGroupId() { public GroupId getContactGroupId() {
return contactGroupId; return contactGroupId;
} }
@Override
public long getLocalTimestamp() { public long getLocalTimestamp() {
return localTimestamp; return local.lastMessageTimestamp;
} }
@Nullable @Nullable
@Override
public MessageId getLastLocalMessageId() { public MessageId getLastLocalMessageId() {
return lastLocalMessageId; return local.lastMessageId;
} }
@Nullable @Nullable
@Override
public MessageId getLastRemoteMessageId() { public MessageId getLastRemoteMessageId() {
return lastRemoteMessageId; return remote.lastMessageId;
} }
Author getIntroducer() { Author getIntroducer() {
return introducer; return introducer;
} }
@Nullable public Local getLocal() {
byte[] getEphemeralPublicKey() { return local;
return ephemeralPublicKey;
} }
@Nullable public Remote getRemote() {
byte[] getEphemeralPrivateKey() { return remote;
return ephemeralPrivateKey;
}
@Nullable
Map<TransportId, TransportProperties> getTransportProperties() {
return transportProperties;
}
long getAcceptTimestamp() {
return acceptTimestamp;
} }
@Nullable @Nullable
@@ -201,27 +179,77 @@ class IntroduceeSession extends Session<IntroduceeState>
return masterKey; return masterKey;
} }
Author getRemoteAuthor() {
return remoteAuthor;
}
@Nullable
byte[] getRemotePublicKey() {
return remoteEphemeralPublicKey;
}
@Nullable
Map<TransportId, TransportProperties> getRemoteTransportProperties() {
return remoteTransportProperties;
}
long getRemoteAcceptTimestamp() {
return remoteAcceptTimestamp;
}
@Nullable @Nullable
Map<TransportId, KeySetId> getTransportKeys() { Map<TransportId, KeySetId> getTransportKeys() {
return transportKeys; 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);
}
}
} }

View File

@@ -440,7 +440,7 @@ class IntroducerProtocolEngine
// Forward ACTIVATE message // Forward ACTIVATE message
Introducee i = getOtherIntroducee(s, m.getGroupId()); Introducee i = getOtherIntroducee(s, m.getGroupId());
long timestamp = getLocalTimestamp(s, i); long timestamp = getLocalTimestamp(s, i);
Message sent = sendActivateMessage(txn, i, timestamp); Message sent = sendActivateMessage(txn, i, timestamp, m.getMac());
// Move to the next state // Move to the next state
IntroducerState state = START; IntroducerState state = START;

View File

@@ -30,16 +30,19 @@ interface IntroductionConstants {
// Session Keys Introducee // Session Keys Introducee
String SESSION_KEY_INTRODUCER = "introducer"; 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_PUBLIC_KEY = "ephemeralPublicKey";
String SESSION_KEY_EPHEMERAL_PRIVATE_KEY = "ephemeralPrivateKey"; String SESSION_KEY_EPHEMERAL_PRIVATE_KEY = "ephemeralPrivateKey";
String SESSION_KEY_TRANSPORT_PROPERTIES = "transportProperties"; String SESSION_KEY_TRANSPORT_PROPERTIES = "transportProperties";
String SESSION_KEY_ACCEPT_TIMESTAMP = "acceptTimestamp"; 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_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";
} }

View File

@@ -30,16 +30,15 @@ interface IntroductionCrypto {
/** /**
* Derives a session master key for Alice or Bob. * Derives a session master key for Alice or Bob.
* *
* @param alice true if the session owner is Alice
* @return The secret master key * @return The secret master key
*/ */
SecretKey deriveMasterKey(IntroduceeSession s, boolean alice) SecretKey deriveMasterKey(IntroduceeSession s)
throws GeneralSecurityException; throws GeneralSecurityException;
/** /**
* Derives a MAC key from the session's master key for Alice or Bob. * 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 * @param alice true for Alice's MAC key, false for Bob's
* @return The MAC key * @return The MAC key
*/ */
@@ -49,17 +48,17 @@ interface IntroductionCrypto {
* Generates a MAC that covers both introducee's ephemeral public keys, * Generates a MAC that covers both introducee's ephemeral public keys,
* transport properties, Author IDs and timestamps of the accept message. * transport properties, Author IDs and timestamps of the accept message.
*/ */
byte[] mac(SecretKey macKey, IntroduceeSession s, AuthorId localAuthorId, byte[] authMac(SecretKey macKey, IntroduceeSession s,
boolean alice); AuthorId localAuthorId, boolean alice);
/** /**
* Verifies a received MAC * Verifies a received MAC
* *
* @param mac The MAC to verify * @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 * @throws GeneralSecurityException if the verification fails
*/ */
void verifyMac(byte[] mac, IntroduceeSession s, AuthorId localAuthorId) void verifyAuthMac(byte[] mac, IntroduceeSession s, AuthorId localAuthorId)
throws GeneralSecurityException; throws GeneralSecurityException;
/** /**
@@ -82,4 +81,17 @@ interface IntroductionCrypto {
void verifySignature(byte[] signature, IntroduceeSession s, void verifySignature(byte[] signature, IntroduceeSession s,
AuthorId localAuthorId) throws GeneralSecurityException; 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;
} }

View File

@@ -23,6 +23,7 @@ import java.util.Map;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; 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_ALICE_MAC_KEY;
import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_MAC; import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_MAC;
import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_NONCE; import static org.briarproject.briar.api.introduction.IntroductionConstants.LABEL_AUTH_NONCE;
@@ -74,10 +75,14 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
@Override @Override
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
public SecretKey deriveMasterKey(IntroduceeSession s, boolean alice) public SecretKey deriveMasterKey(IntroduceeSession s)
throws GeneralSecurityException { throws GeneralSecurityException {
return deriveMasterKey(s.getEphemeralPublicKey(), return deriveMasterKey(
s.getEphemeralPrivateKey(), s.getRemotePublicKey(), alice); s.getLocal().ephemeralPublicKey,
s.getLocal().ephemeralPrivateKey,
s.getRemote().ephemeralPublicKey,
s.getLocal().alice
);
} }
SecretKey deriveMasterKey(byte[] publicKey, byte[] privateKey, SecretKey deriveMasterKey(byte[] publicKey, byte[] privateKey,
@@ -108,16 +113,17 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
@Override @Override
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
public byte[] mac(SecretKey macKey, IntroduceeSession s, public byte[] authMac(SecretKey macKey, IntroduceeSession s,
AuthorId localAuthorId, boolean alice) { AuthorId localAuthorId, boolean alice) {
return mac(macKey, s.getIntroducer().getId(), localAuthorId, return authMac(macKey, s.getIntroducer().getId(), localAuthorId,
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(), s.getRemote().author.getId(), s.getLocal().acceptTimestamp,
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(), s.getRemote().acceptTimestamp, s.getLocal().ephemeralPublicKey,
s.getRemotePublicKey(), s.getTransportProperties(), s.getRemote().ephemeralPublicKey,
s.getRemoteTransportProperties(), alice); s.getLocal().transportProperties,
s.getRemote().transportProperties, alice);
} }
byte[] mac(SecretKey macKey, AuthorId introducerId, byte[] authMac(SecretKey macKey, AuthorId introducerId,
AuthorId localAuthorId, AuthorId remoteAuthorId, AuthorId localAuthorId, AuthorId remoteAuthorId,
long acceptTimestamp, long remoteAcceptTimestamp, long acceptTimestamp, long remoteAcceptTimestamp,
byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey, byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey,
@@ -125,7 +131,7 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
Map<TransportId, TransportProperties> remoteTransportProperties, Map<TransportId, TransportProperties> remoteTransportProperties,
boolean alice) { boolean alice) {
byte[] inputs = byte[] inputs =
getMacInputs(introducerId, localAuthorId, remoteAuthorId, getAuthMacInputs(introducerId, localAuthorId, remoteAuthorId,
acceptTimestamp, remoteAcceptTimestamp, acceptTimestamp, remoteAcceptTimestamp,
ephemeralPublicKey, remoteEphemeralPublicKey, ephemeralPublicKey, remoteEphemeralPublicKey,
transportProperties, remoteTransportProperties, alice); transportProperties, remoteTransportProperties, alice);
@@ -138,19 +144,20 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
@Override @Override
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
public void verifyMac(byte[] mac, IntroduceeSession s, public void verifyAuthMac(byte[] mac, IntroduceeSession s,
AuthorId localAuthorId) AuthorId localAuthorId)
throws GeneralSecurityException { throws GeneralSecurityException {
boolean alice = isAlice(localAuthorId, s.getRemoteAuthor().getId()); boolean alice = isAlice(localAuthorId, s.getRemote().author.getId());
verifyMac(mac, new SecretKey(s.getMasterKey()), verifyAuthMac(mac, new SecretKey(s.getRemote().macKey),
s.getIntroducer().getId(), localAuthorId, s.getIntroducer().getId(), localAuthorId,
s.getRemoteAuthor().getId(), s.getAcceptTimestamp(), s.getRemote().author.getId(), s.getLocal().acceptTimestamp,
s.getRemoteAcceptTimestamp(), s.getEphemeralPublicKey(), s.getRemote().acceptTimestamp, s.getLocal().ephemeralPublicKey,
s.getRemotePublicKey(), s.getTransportProperties(), s.getRemote().ephemeralPublicKey,
s.getRemoteTransportProperties(), !alice); s.getLocal().transportProperties,
s.getRemote().transportProperties, !alice);
} }
void verifyMac(byte[] mac, SecretKey masterKey, void verifyAuthMac(byte[] mac, SecretKey macKey,
AuthorId introducerId, AuthorId localAuthorId, AuthorId introducerId, AuthorId localAuthorId,
AuthorId remoteAuthorId, long acceptTimestamp, AuthorId remoteAuthorId, long acceptTimestamp,
long remoteAcceptTimestamp, byte[] ephemeralPublicKey, long remoteAcceptTimestamp, byte[] ephemeralPublicKey,
@@ -158,9 +165,8 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
Map<TransportId, TransportProperties> transportProperties, Map<TransportId, TransportProperties> transportProperties,
Map<TransportId, TransportProperties> remoteTransportProperties, Map<TransportId, TransportProperties> remoteTransportProperties,
boolean alice) throws GeneralSecurityException { boolean alice) throws GeneralSecurityException {
SecretKey macKey = deriveMacKey(masterKey, alice);
byte[] inputs = byte[] inputs =
getMacInputs(introducerId, localAuthorId, remoteAuthorId, getAuthMacInputs(introducerId, localAuthorId, remoteAuthorId,
acceptTimestamp, remoteAcceptTimestamp, acceptTimestamp, remoteAcceptTimestamp,
ephemeralPublicKey, remoteEphemeralPublicKey, ephemeralPublicKey, remoteEphemeralPublicKey,
transportProperties, remoteTransportProperties, !alice); 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, AuthorId localAuthorId, AuthorId remoteAuthorId,
long acceptTimestamp, long remoteAcceptTimestamp, long acceptTimestamp, long remoteAcceptTimestamp,
byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey, byte[] ephemeralPublicKey, byte[] remoteEphemeralPublicKey,
@@ -214,9 +220,8 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
public void verifySignature(byte[] signature, IntroduceeSession s, public void verifySignature(byte[] signature, IntroduceeSession s,
AuthorId localAuthorId) throws GeneralSecurityException { AuthorId localAuthorId) throws GeneralSecurityException {
boolean alice = isAlice(s.getRemoteAuthor().getId(), localAuthorId); SecretKey macKey = new SecretKey(s.getRemote().macKey);
SecretKey macKey = deriveMacKey(new SecretKey(s.getMasterKey()), alice); verifySignature(macKey, s.getRemote().author.getPublicKey(), signature);
verifySignature(macKey, s.getRemoteAuthor().getPublicKey(), signature);
} }
void verifySignature(SecretKey macKey, byte[] publicKey, void verifySignature(SecretKey macKey, byte[] publicKey,
@@ -232,4 +237,33 @@ class IntroductionCryptoImpl implements IntroductionCrypto {
return crypto.mac(LABEL_AUTH_NONCE, macKey); 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();
}
}
} }

View File

@@ -190,8 +190,10 @@ class IntroductionManagerImpl extends ConversationClientImpl
Author remote = messageParser.parseRequestMessage(m, body).getAuthor(); Author remote = messageParser.parseRequestMessage(m, body).getAuthor();
if (local.equals(remote)) throw new FormatException(); if (local.equals(remote)) throw new FormatException();
SessionId sessionId = crypto.getSessionId(introducer, local, remote); SessionId sessionId = crypto.getSessionId(introducer, local, remote);
boolean alice = crypto.isAlice(local.getId(), remote.getId());
return IntroduceeSession 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, private <S extends Session> S handleMessage(Transaction txn, Message m,
@@ -441,7 +443,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
IntroduceeSession session = sessionParser IntroduceeSession session = sessionParser
.parseIntroduceeSession(contactGroupId, bdfSession); .parseIntroduceeSession(contactGroupId, bdfSession);
sessionId = session.getSessionId(); sessionId = session.getSessionId();
author = session.getRemoteAuthor(); author = session.getRemote().author;
} else throw new AssertionError(); } else throw new AssertionError();
Message msg = clientHelper.getMessage(txn, m); Message msg = clientHelper.getMessage(txn, m);
BdfList body = clientHelper.getMessageAsList(txn, m); BdfList body = clientHelper.getMessageAsList(txn, m);
@@ -481,7 +483,7 @@ class IntroductionManagerImpl extends ConversationClientImpl
IntroduceeSession session = sessionParser IntroduceeSession session = sessionParser
.parseIntroduceeSession(contactGroupId, bdfSession); .parseIntroduceeSession(contactGroupId, bdfSession);
sessionId = session.getSessionId(); sessionId = session.getSessionId();
author = session.getRemoteAuthor(); author = session.getRemote().author;
} else throw new AssertionError(); } else throw new AssertionError();
return new IntroductionResponse(sessionId, m, contactGroupId, return new IntroductionResponse(sessionId, m, contactGroupId,
role, meta.getTimestamp(), meta.isLocal(), status.isSent(), role, meta.getTimestamp(), meta.isLocal(), status.isSent(),

View File

@@ -27,6 +27,7 @@ import static org.briarproject.bramble.util.ValidationUtils.checkLength;
import static org.briarproject.bramble.util.ValidationUtils.checkSize; 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.api.introduction.IntroductionConstants.MAX_REQUEST_MESSAGE_LENGTH;
import static org.briarproject.briar.introduction.MessageType.ACCEPT; import static org.briarproject.briar.introduction.MessageType.ACCEPT;
import static org.briarproject.briar.introduction.MessageType.ACTIVATE;
import static org.briarproject.briar.introduction.MessageType.AUTH; import static org.briarproject.briar.introduction.MessageType.AUTH;
@@ -55,8 +56,9 @@ class IntroductionValidator extends BdfMessageValidator {
return validateAcceptMessage(m, body); return validateAcceptMessage(m, body);
case AUTH: case AUTH:
return validateAuthMessage(m, body); return validateAuthMessage(m, body);
case DECLINE:
case ACTIVATE: case ACTIVATE:
return validateActivateMessage(m, body);
case DECLINE:
case ABORT: case ABORT:
return validateOtherMessage(type, m, body); return validateOtherMessage(type, m, body);
default: default:
@@ -149,6 +151,32 @@ class IntroductionValidator extends BdfMessageValidator {
Collections.singletonList(dependency)); 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, private BdfMessageContext validateOtherMessage(MessageType type,
Message m, BdfList body) throws FormatException { Message m, BdfList body) throws FormatException {
checkSize(body, 3); checkSize(body, 3);

View File

@@ -47,7 +47,8 @@ interface MessageEncoder {
byte[] mac, byte[] signature); byte[] mac, byte[] signature);
Message encodeActivateMessage(GroupId contactGroupId, long timestamp, Message encodeActivateMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId); @Nullable MessageId previousMessageId, SessionId sessionId,
byte[] mac);
Message encodeAbortMessage(GroupId contactGroupId, long timestamp, Message encodeAbortMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId); @Nullable MessageId previousMessageId, SessionId sessionId);

View File

@@ -100,12 +100,7 @@ class MessageEncoderImpl implements MessageEncoder {
clientHelper.toList(author), clientHelper.toList(author),
message message
); );
try { return createMessage(contactGroupId, timestamp, body);
return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body));
} catch (FormatException e) {
throw new AssertionError(e);
}
} }
@Override @Override
@@ -119,14 +114,9 @@ class MessageEncoderImpl implements MessageEncoder {
previousMessageId, previousMessageId,
ephemeralPublicKey, ephemeralPublicKey,
acceptTimestamp, acceptTimestamp,
encodeTransportProperties(transportProperties) clientHelper.toDictionary(transportProperties)
); );
try { return createMessage(contactGroupId, timestamp, body);
return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body));
} catch (FormatException e) {
throw new AssertionError(e);
}
} }
@Override @Override
@@ -147,19 +137,20 @@ class MessageEncoderImpl implements MessageEncoder {
mac, mac,
signature signature
); );
try { return createMessage(contactGroupId, timestamp, body);
return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body));
} catch (FormatException e) {
throw new AssertionError(e);
}
} }
@Override @Override
public Message encodeActivateMessage(GroupId contactGroupId, long timestamp, public Message encodeActivateMessage(GroupId contactGroupId, long timestamp,
@Nullable MessageId previousMessageId, SessionId sessionId) { @Nullable MessageId previousMessageId, SessionId sessionId,
return encodeMessage(ACTIVATE, contactGroupId, sessionId, timestamp, byte[] mac) {
previousMessageId); BdfList body = BdfList.of(
ACTIVATE.getValue(),
sessionId,
previousMessageId,
mac
);
return createMessage(contactGroupId, timestamp, body);
} }
@Override @Override
@@ -177,6 +168,11 @@ class MessageEncoderImpl implements MessageEncoder {
sessionId, sessionId,
previousMessageId previousMessageId
); );
return createMessage(contactGroupId, timestamp, body);
}
private Message createMessage(GroupId contactGroupId, long timestamp,
BdfList body) {
try { try {
return messageFactory.createMessage(contactGroupId, timestamp, return messageFactory.createMessage(contactGroupId, timestamp,
clientHelper.toByteArray(body)); 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;
}
} }

View File

@@ -124,8 +124,9 @@ class MessageParserImpl implements MessageParser {
SessionId sessionId = new SessionId(body.getRaw(1)); SessionId sessionId = new SessionId(body.getRaw(1));
byte[] previousMsgBytes = body.getRaw(2); byte[] previousMsgBytes = body.getRaw(2);
MessageId previousMessageId = new MessageId(previousMsgBytes); MessageId previousMessageId = new MessageId(previousMsgBytes);
byte[] mac = body.getRaw(3);
return new ActivateMessage(m.getId(), m.getGroupId(), m.getTimestamp(), return new ActivateMessage(m.getId(), m.getGroupId(), m.getTimestamp(),
previousMessageId, sessionId); previousMessageId, sessionId, mac);
} }
@Override @Override

View File

@@ -12,7 +12,7 @@ abstract class Session<S extends State> {
private final SessionId sessionId; private final SessionId sessionId;
private final S state; private final S state;
private long requestTimestamp; private final long requestTimestamp;
Session(SessionId sessionId, S state, long requestTimestamp) { Session(SessionId sessionId, S state, long requestTimestamp) {
this.sessionId = sessionId; this.sessionId = sessionId;
@@ -30,7 +30,7 @@ abstract class Session<S extends State> {
return state; return state;
} }
public long getRequestTimestamp() { long getRequestTimestamp() {
return requestTimestamp; return requestTimestamp;
} }

View File

@@ -7,6 +7,9 @@ import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.transport.KeySetId; 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 org.briarproject.briar.introduction.IntroducerSession.Introducee;
import java.util.Map; 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.INTRODUCEE;
import static org.briarproject.briar.api.introduction.Role.INTRODUCER; 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_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_AUTHOR;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY; import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_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_INTRODUCER;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; 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_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_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_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_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_REQUEST_TIMESTAMP;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE; 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_SESSION_ID;
@@ -91,34 +95,43 @@ class SessionEncoderImpl implements SessionEncoder {
@Override @Override
public BdfDictionary encodeIntroduceeSession(IntroduceeSession s) { public BdfDictionary encodeIntroduceeSession(IntroduceeSession s) {
BdfDictionary d = encodeSession(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_INTRODUCER, clientHelper.toList(s.getIntroducer()));
d.put(SESSION_KEY_REMOTE_AUTHOR, d.put(SESSION_KEY_LOCAL, encodeLocal(s.getLocal()));
clientHelper.toList(s.getRemoteAuthor())); d.put(SESSION_KEY_REMOTE, encodeRemote(s.getRemote()));
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());
putNullable(d, SESSION_KEY_MASTER_KEY, s.getMasterKey()); 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, putNullable(d, SESSION_KEY_TRANSPORT_KEYS,
encodeTransportKeys(s.getTransportKeys())); encodeTransportKeys(s.getTransportKeys()));
return d; 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) { private BdfDictionary encodeSession(Session s) {
BdfDictionary d = new BdfDictionary(); BdfDictionary d = new BdfDictionary();
d.put(SESSION_KEY_SESSION_ID, s.getSessionId()); d.put(SESSION_KEY_SESSION_ID, s.getSessionId());

View File

@@ -13,6 +13,8 @@ import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.transport.KeySetId; import org.briarproject.bramble.api.transport.KeySetId;
import org.briarproject.briar.api.client.SessionId; import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.introduction.Role; 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 org.briarproject.briar.introduction.IntroducerSession.Introducee;
import java.util.HashMap; import java.util.HashMap;
@@ -22,7 +24,10 @@ import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
import javax.inject.Inject; 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_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_AUTHOR;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY; import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_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_INTRODUCER;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; 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_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_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_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_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_REQUEST_TIMESTAMP;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE; 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_SESSION_ID;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_STATE; 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_KEYS;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_TRANSPORT_PROPERTIES; 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 @Immutable
@NotNullByDefault @NotNullByDefault
@@ -103,42 +106,55 @@ class SessionParserImpl implements SessionParser {
SessionId sessionId = getSessionId(d); SessionId sessionId = getSessionId(d);
IntroduceeState state = IntroduceeState.fromValue(getState(d)); IntroduceeState state = IntroduceeState.fromValue(getState(d));
long requestTimestamp = d.getLong(SESSION_KEY_REQUEST_TIMESTAMP); 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 = MessageId lastLocalMessageId =
getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID); getMessageId(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID);
long localTimestamp = d.getLong(SESSION_KEY_LOCAL_TIMESTAMP); 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 = byte[] ephemeralPublicKey =
d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY); d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PUBLIC_KEY);
BdfDictionary tpDict =
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES);
byte[] ephemeralPrivateKey = byte[] ephemeralPrivateKey =
d.getOptionalRaw(SESSION_KEY_EPHEMERAL_PRIVATE_KEY); 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 = BdfDictionary tpDict =
d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES); d.getOptionalDictionary(SESSION_KEY_TRANSPORT_PROPERTIES);
Map<TransportId, TransportProperties> transportProperties = Map<TransportId, TransportProperties> transportProperties =
tpDict == null ? null : clientHelper tpDict == null ? null : clientHelper
.parseAndValidateTransportPropertiesMap(tpDict); .parseAndValidateTransportPropertiesMap(tpDict);
long acceptTimestamp = d.getLong(SESSION_KEY_ACCEPT_TIMESTAMP); long acceptTimestamp = d.getLong(SESSION_KEY_ACCEPT_TIMESTAMP);
byte[] masterKey = d.getOptionalRaw(SESSION_KEY_MASTER_KEY); byte[] macKey = d.getOptionalRaw(SESSION_KEY_MAC_KEY);
Author remoteAuthor = getAuthor(d, SESSION_KEY_REMOTE_AUTHOR); return new Remote(alice, remoteAuthor, lastRemoteMessageId,
byte[] remoteEphemeralPublicKey = ephemeralPublicKey, transportProperties, acceptTimestamp,
d.getOptionalRaw(SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY); macKey);
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);
} }
private int getState(BdfDictionary d) throws FormatException { private int getState(BdfDictionary d) throws FormatException {

View File

@@ -96,35 +96,35 @@ public class IntroductionCryptoImplTest extends BrambleTestCase {
} }
@Test @Test
public void testAliceMac() throws Exception { public void testAliceAuthMac() throws Exception {
SecretKey aliceMacKey = crypto.deriveMacKey(masterKey, true); SecretKey aliceMacKey = crypto.deriveMacKey(masterKey, true);
byte[] aliceMac = byte[] aliceMac =
crypto.mac(aliceMacKey, introducer.getId(), alice.getId(), crypto.authMac(aliceMacKey, introducer.getId(), alice.getId(),
bob.getId(), aliceAcceptTimestamp, bobAcceptTimestamp, bob.getId(), aliceAcceptTimestamp, bobAcceptTimestamp,
aliceEphemeral.getPublic().getEncoded(), aliceEphemeral.getPublic().getEncoded(),
bobEphemeral.getPublic().getEncoded(), aliceTransport, bobEphemeral.getPublic().getEncoded(), aliceTransport,
bobTransport, true); bobTransport, true);
crypto.verifyMac(aliceMac, masterKey, introducer.getId(), bob.getId(), crypto.verifyAuthMac(aliceMac, aliceMacKey, introducer.getId(),
alice.getId(), bobAcceptTimestamp, aliceAcceptTimestamp, bob.getId(), alice.getId(), bobAcceptTimestamp,
bobEphemeral.getPublic().getEncoded(), aliceAcceptTimestamp, bobEphemeral.getPublic().getEncoded(),
aliceEphemeral.getPublic().getEncoded(), bobTransport, aliceEphemeral.getPublic().getEncoded(), bobTransport,
aliceTransport, true); aliceTransport, true);
} }
@Test @Test
public void testBobMac() throws Exception { public void testBobAuthMac() throws Exception {
SecretKey bobMacKey = crypto.deriveMacKey(masterKey, false); SecretKey bobMacKey = crypto.deriveMacKey(masterKey, false);
byte[] bobMac = byte[] bobMac =
crypto.mac(bobMacKey, introducer.getId(), bob.getId(), crypto.authMac(bobMacKey, introducer.getId(), bob.getId(),
alice.getId(), bobAcceptTimestamp, aliceAcceptTimestamp, alice.getId(), bobAcceptTimestamp, aliceAcceptTimestamp,
bobEphemeral.getPublic().getEncoded(), bobEphemeral.getPublic().getEncoded(),
aliceEphemeral.getPublic().getEncoded(), bobTransport, aliceEphemeral.getPublic().getEncoded(), bobTransport,
aliceTransport, false); aliceTransport, false);
crypto.verifyMac(bobMac, masterKey, introducer.getId(), alice.getId(), crypto.verifyAuthMac(bobMac, bobMacKey, introducer.getId(),
bob.getId(), aliceAcceptTimestamp, bobAcceptTimestamp, alice.getId(), bob.getId(), aliceAcceptTimestamp,
aliceEphemeral.getPublic().getEncoded(), bobAcceptTimestamp, aliceEphemeral.getPublic().getEncoded(),
bobEphemeral.getPublic().getEncoded(), aliceTransport, bobEphemeral.getPublic().getEncoded(), aliceTransport,
bobTransport, false); bobTransport, false);
} }
@@ -139,4 +139,20 @@ public class IntroductionCryptoImplTest extends BrambleTestCase {
signature); 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);
}
} }

View File

@@ -170,16 +170,6 @@ public class IntroductionIntegrationTest
sync1To0(1, true); sync1To0(1, true);
sync0To2(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 // assert that introducee2 did add the transport keys
IntroduceeSession session2 = getIntroduceeSession(c2.getClientHelper(), IntroduceeSession session2 = getIntroduceeSession(c2.getClientHelper(),
introductionManager2.getContactGroup(contact0From2).getId()); introductionManager2.getContactGroup(contact0From2).getId());
@@ -194,7 +184,7 @@ public class IntroductionIntegrationTest
IntroduceeSession session1 = getIntroduceeSession(c1.getClientHelper(), IntroduceeSession session1 = getIntroduceeSession(c1.getClientHelper(),
introductionManager1.getContactGroup(contact0From1).getId()); introductionManager1.getContactGroup(contact0From1).getId());
assertNull(session1.getMasterKey()); assertNull(session1.getMasterKey());
assertNull(session1.getEphemeralPrivateKey()); assertNull(session1.getLocal().ephemeralPrivateKey);
assertNull(session1.getTransportKeys()); assertNull(session1.getTransportKeys());
// sync second ACTIVATE and its forward // sync second ACTIVATE and its forward
@@ -533,16 +523,6 @@ public class IntroductionIntegrationTest
sync1To0(1, true); sync1To0(1, true);
sync0To2(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 // sync second AUTH and its forward as well as the following ACTIVATE
sync2To0(2, true); sync2To0(2, true);
sync0To1(2, true); sync0To1(2, true);

View File

@@ -312,7 +312,7 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
@Test @Test
public void testAcceptsActivate() throws Exception { public void testAcceptsActivate() throws Exception {
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes()); previousMsgId.getBytes(), mac);
expectEncodeMetadata(ACTIVATE); expectEncodeMetadata(ACTIVATE);
BdfMessageContext messageContext = BdfMessageContext messageContext =
@@ -323,27 +323,37 @@ public class IntroductionValidatorTest extends ValidatorTestCase {
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testRejectsTooShortBodyForActivate() throws Exception { 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); validator.validateMessage(message, group, body);
} }
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testRejectsTooLongBodyForActivate() throws Exception { public void testRejectsTooLongBodyForActivate() throws Exception {
BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(), BdfList body = BdfList.of(ACTIVATE.getValue(), sessionId.getBytes(),
previousMsgId.getBytes(), null); previousMsgId.getBytes(), mac, null);
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testRejectsInvalidSessionIdForActivate() throws Exception { public void testRejectsInvalidSessionIdForActivate() throws Exception {
BdfList body = BdfList body =
BdfList.of(ACTIVATE.getValue(), null, previousMsgId.getBytes()); BdfList.of(ACTIVATE.getValue(), null, previousMsgId.getBytes(),
mac);
validator.validateMessage(message, group, body); validator.validateMessage(message, group, body);
} }
@Test(expected = FormatException.class) @Test(expected = FormatException.class)
public void testRejectsInvalidPreviousMsgIdForActivate() throws Exception { 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); validator.validateMessage(message, group, body);
} }

View File

@@ -165,17 +165,17 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
sessionId, ephemeralPublicKey, acceptTimestamp, sessionId, ephemeralPublicKey, acceptTimestamp,
transportProperties); transportProperties);
validator.validateMessage(m, group, clientHelper.toList(m)); validator.validateMessage(m, group, clientHelper.toList(m));
AcceptMessage rm = AcceptMessage am =
messageParser.parseAcceptMessage(m, clientHelper.toList(m)); messageParser.parseAcceptMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), rm.getMessageId()); assertEquals(m.getId(), am.getMessageId());
assertEquals(m.getGroupId(), rm.getGroupId()); assertEquals(m.getGroupId(), am.getGroupId());
assertEquals(m.getTimestamp(), rm.getTimestamp()); assertEquals(m.getTimestamp(), am.getTimestamp());
assertEquals(previousMsgId, rm.getPreviousMessageId()); assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, rm.getSessionId()); assertEquals(sessionId, am.getSessionId());
assertArrayEquals(ephemeralPublicKey, rm.getEphemeralPublicKey()); assertArrayEquals(ephemeralPublicKey, am.getEphemeralPublicKey());
assertEquals(acceptTimestamp, rm.getAcceptTimestamp()); assertEquals(acceptTimestamp, am.getAcceptTimestamp());
assertEquals(transportProperties, rm.getTransportProperties()); assertEquals(transportProperties, am.getTransportProperties());
} }
@Test @Test
@@ -184,14 +184,14 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
.encodeDeclineMessage(groupId, timestamp, previousMsgId, .encodeDeclineMessage(groupId, timestamp, previousMsgId,
sessionId); sessionId);
validator.validateMessage(m, group, clientHelper.toList(m)); validator.validateMessage(m, group, clientHelper.toList(m));
DeclineMessage rm = DeclineMessage dm =
messageParser.parseDeclineMessage(m, clientHelper.toList(m)); messageParser.parseDeclineMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), rm.getMessageId()); assertEquals(m.getId(), dm.getMessageId());
assertEquals(m.getGroupId(), rm.getGroupId()); assertEquals(m.getGroupId(), dm.getGroupId());
assertEquals(m.getTimestamp(), rm.getTimestamp()); assertEquals(m.getTimestamp(), dm.getTimestamp());
assertEquals(previousMsgId, rm.getPreviousMessageId()); assertEquals(previousMsgId, dm.getPreviousMessageId());
assertEquals(sessionId, rm.getSessionId()); assertEquals(sessionId, dm.getSessionId());
} }
@Test @Test
@@ -200,32 +200,33 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
.encodeAuthMessage(groupId, timestamp, previousMsgId, .encodeAuthMessage(groupId, timestamp, previousMsgId,
sessionId, mac, signature); sessionId, mac, signature);
validator.validateMessage(m, group, clientHelper.toList(m)); validator.validateMessage(m, group, clientHelper.toList(m));
AuthMessage rm = AuthMessage am =
messageParser.parseAuthMessage(m, clientHelper.toList(m)); messageParser.parseAuthMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), rm.getMessageId()); assertEquals(m.getId(), am.getMessageId());
assertEquals(m.getGroupId(), rm.getGroupId()); assertEquals(m.getGroupId(), am.getGroupId());
assertEquals(m.getTimestamp(), rm.getTimestamp()); assertEquals(m.getTimestamp(), am.getTimestamp());
assertEquals(previousMsgId, rm.getPreviousMessageId()); assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, rm.getSessionId()); assertEquals(sessionId, am.getSessionId());
assertArrayEquals(mac, rm.getMac()); assertArrayEquals(mac, am.getMac());
assertArrayEquals(signature, rm.getSignature()); assertArrayEquals(signature, am.getSignature());
} }
@Test @Test
public void testActivateMessage() throws Exception { public void testActivateMessage() throws Exception {
Message m = messageEncoder Message m = messageEncoder
.encodeActivateMessage(groupId, timestamp, previousMsgId, .encodeActivateMessage(groupId, timestamp, previousMsgId,
sessionId); sessionId, mac);
validator.validateMessage(m, group, clientHelper.toList(m)); validator.validateMessage(m, group, clientHelper.toList(m));
ActivateMessage rm = ActivateMessage am =
messageParser.parseActivateMessage(m, clientHelper.toList(m)); messageParser.parseActivateMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), rm.getMessageId()); assertEquals(m.getId(), am.getMessageId());
assertEquals(m.getGroupId(), rm.getGroupId()); assertEquals(m.getGroupId(), am.getGroupId());
assertEquals(m.getTimestamp(), rm.getTimestamp()); assertEquals(m.getTimestamp(), am.getTimestamp());
assertEquals(previousMsgId, rm.getPreviousMessageId()); assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, rm.getSessionId()); assertEquals(sessionId, am.getSessionId());
assertArrayEquals(mac, am.getMac());
} }
@Test @Test
@@ -234,14 +235,14 @@ public class MessageEncoderParserIntegrationTest extends BrambleTestCase {
.encodeAbortMessage(groupId, timestamp, previousMsgId, .encodeAbortMessage(groupId, timestamp, previousMsgId,
sessionId); sessionId);
validator.validateMessage(m, group, clientHelper.toList(m)); validator.validateMessage(m, group, clientHelper.toList(m));
AbortMessage rm = AbortMessage am =
messageParser.parseAbortMessage(m, clientHelper.toList(m)); messageParser.parseAbortMessage(m, clientHelper.toList(m));
assertEquals(m.getId(), rm.getMessageId()); assertEquals(m.getId(), am.getMessageId());
assertEquals(m.getGroupId(), rm.getGroupId()); assertEquals(m.getGroupId(), am.getGroupId());
assertEquals(m.getTimestamp(), rm.getTimestamp()); assertEquals(m.getTimestamp(), am.getTimestamp());
assertEquals(previousMsgId, rm.getPreviousMessageId()); assertEquals(previousMsgId, am.getPreviousMessageId());
assertEquals(sessionId, rm.getSessionId()); assertEquals(sessionId, am.getSessionId());
} }
} }

View File

@@ -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.getRandomId;
import static org.briarproject.bramble.test.TestUtils.getTransportId; import static org.briarproject.bramble.test.TestUtils.getTransportId;
import static org.briarproject.bramble.test.TestUtils.getTransportPropertiesMap; 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.IntroduceeState.LOCAL_ACCEPTED;
import static org.briarproject.briar.introduction.IntroducerState.AWAIT_AUTHS; import static org.briarproject.briar.introduction.IntroducerState.AWAIT_AUTHS;
import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE; import static org.briarproject.briar.introduction.IntroductionConstants.SESSION_KEY_ROLE;
import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; import static org.briarproject.briar.test.BriarTestUtils.getRealAuthor;
import static org.briarproject.briar.api.introduction.Role.INTRODUCER;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class SessionEncoderParserIntegrationTest extends BrambleTestCase { public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
@@ -74,6 +78,8 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
private final Map<TransportId, TransportProperties> private final Map<TransportId, TransportProperties>
remoteTransportProperties = getTransportPropertiesMap(3); remoteTransportProperties = getTransportPropertiesMap(3);
private final Map<TransportId, KeySetId> transportKeys = new HashMap<>(); private final Map<TransportId, KeySetId> transportKeys = new HashMap<>();
private final byte[] localMacKey = getRandomBytes(SecretKey.LENGTH);
private final byte[] remoteMacKey = getRandomBytes(SecretKey.LENGTH);
public SessionEncoderParserIntegrationTest() { public SessionEncoderParserIntegrationTest() {
BriarIntegrationTestComponent component = BriarIntegrationTestComponent component =
@@ -82,8 +88,8 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
sessionEncoder = new SessionEncoderImpl(clientHelper); sessionEncoder = new SessionEncoderImpl(clientHelper);
sessionParser = new SessionParserImpl(clientHelper); sessionParser = new SessionParserImpl(clientHelper);
author1 = getRealAuthor(); author1 = getRealAuthor(authorFactory);
author2 = getRealAuthor(); author2 = getRealAuthor(authorFactory);
transportKeys.put(getTransportId(), new KeySetId(1)); transportKeys.put(getTransportId(), new KeySetId(1));
transportKeys.put(getTransportId(), new KeySetId(2)); transportKeys.put(getTransportId(), new KeySetId(2));
transportKeys.put(getTransportId(), new KeySetId(3)); transportKeys.put(getTransportId(), new KeySetId(3));
@@ -167,48 +173,70 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(s1.getSessionId(), s2.getSessionId()); assertEquals(s1.getSessionId(), s2.getSessionId());
assertEquals(groupId1, s1.getContactGroupId()); assertEquals(groupId1, s1.getContactGroupId());
assertEquals(s1.getContactGroupId(), s2.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(localTimestamp, s1.getLocalTimestamp());
assertEquals(s1.getLocalTimestamp(), s2.getLocalTimestamp()); assertEquals(s1.getLocalTimestamp(), s2.getLocalTimestamp());
assertEquals(lastLocalMessageId, s1.getLastLocalMessageId()); assertEquals(lastLocalMessageId, s1.getLastLocalMessageId());
assertEquals(s1.getLastLocalMessageId(), s2.getLastLocalMessageId()); assertEquals(s1.getLastLocalMessageId(), s2.getLastLocalMessageId());
assertEquals(lastRemoteMessageId, s1.getLastRemoteMessageId()); assertEquals(lastRemoteMessageId, s1.getLastRemoteMessageId());
assertEquals(s1.getLastRemoteMessageId(), s2.getLastRemoteMessageId()); assertEquals(s1.getLastRemoteMessageId(), s2.getLastRemoteMessageId());
assertEquals(author1, s1.getIntroducer());
assertEquals(s1.getIntroducer(), s2.getIntroducer()); // check local
assertEquals(author2, s1.getRemoteAuthor()); assertTrue(s1.getLocal().alice);
assertEquals(s1.getRemoteAuthor(), s2.getRemoteAuthor()); assertEquals(s1.getLocal().alice, s2.getLocal().alice);
assertArrayEquals(ephemeralPublicKey, s1.getEphemeralPublicKey()); assertEquals(lastLocalMessageId, s1.getLocal().lastMessageId);
assertArrayEquals(s1.getEphemeralPublicKey(), assertEquals(s1.getLocal().lastMessageId, s2.getLocal().lastMessageId);
s2.getEphemeralPublicKey()); assertEquals(localTimestamp, s1.getLocal().lastMessageTimestamp);
assertArrayEquals(ephemeralPrivateKey, s1.getEphemeralPrivateKey()); assertEquals(s1.getLocal().lastMessageTimestamp,
assertArrayEquals(s1.getEphemeralPrivateKey(), s2.getLocal().lastMessageTimestamp);
s2.getEphemeralPrivateKey()); assertArrayEquals(ephemeralPublicKey, s1.getLocal().ephemeralPublicKey);
assertEquals(acceptTimestamp, s1.getAcceptTimestamp()); assertArrayEquals(s1.getLocal().ephemeralPublicKey,
assertEquals(s1.getAcceptTimestamp(), s2.getAcceptTimestamp()); s2.getLocal().ephemeralPublicKey);
assertArrayEquals(masterKey, s1.getMasterKey()); assertArrayEquals(ephemeralPrivateKey,
assertArrayEquals(s1.getMasterKey(), s2.getMasterKey()); s1.getLocal().ephemeralPrivateKey);
assertArrayEquals(remoteEphemeralPublicKey, s1.getRemotePublicKey()); assertArrayEquals(s1.getLocal().ephemeralPrivateKey,
assertArrayEquals(s1.getRemotePublicKey(), s2.getLocal().ephemeralPrivateKey);
s2.getRemotePublicKey()); assertEquals(transportProperties, s1.getLocal().transportProperties);
assertEquals(transportProperties, s1.getTransportProperties()); assertEquals(s1.getLocal().transportProperties,
assertEquals(s1.getTransportProperties(), s2.getTransportProperties()); 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, assertEquals(remoteTransportProperties,
s1.getRemoteTransportProperties()); s1.getRemote().transportProperties);
assertEquals(s1.getRemoteTransportProperties(), assertEquals(s1.getRemote().transportProperties,
s2.getRemoteTransportProperties()); s2.getRemote().transportProperties);
assertEquals(remoteAcceptTimestamp, s1.getRemoteAcceptTimestamp()); assertEquals(remoteAcceptTimestamp, s1.getRemote().acceptTimestamp);
assertEquals(s1.getRemoteAcceptTimestamp(), s2.getRemoteAcceptTimestamp()); assertEquals(s1.getRemote().acceptTimestamp,
assertEquals(transportKeys, s1.getTransportKeys()); s2.getRemote().acceptTimestamp);
assertEquals(s1.getTransportKeys(), s2.getTransportKeys()); assertArrayEquals(remoteMacKey, s1.getRemote().macKey);
assertArrayEquals(s1.getRemote().macKey, s2.getRemote().macKey);
} }
@Test @Test
public void testIntroduceeSessionWithNulls() throws FormatException { public void testIntroduceeSessionWithNulls() throws FormatException {
IntroduceeSession s1 = IntroduceeSession s1 = IntroduceeSession
new IntroduceeSession(sessionId, LOCAL_ACCEPTED, .getInitial(groupId1, sessionId, author1, false, author2);
requestTimestamp, groupId1, null, localTimestamp, null,
author1, null, null, null, acceptTimestamp, null,
author2, null, null, remoteAcceptTimestamp, null);
BdfDictionary d = sessionEncoder.encodeIntroduceeSession(s1); BdfDictionary d = sessionEncoder.encodeIntroduceeSession(s1);
IntroduceeSession s2 = IntroduceeSession s2 =
@@ -218,14 +246,38 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(s1.getLastLocalMessageId(), s2.getLastLocalMessageId()); assertEquals(s1.getLastLocalMessageId(), s2.getLastLocalMessageId());
assertNull(s1.getLastRemoteMessageId()); assertNull(s1.getLastRemoteMessageId());
assertEquals(s1.getLastRemoteMessageId(), s2.getLastRemoteMessageId()); assertEquals(s1.getLastRemoteMessageId(), s2.getLastRemoteMessageId());
assertNull(s1.getEphemeralPublicKey()); assertNull(s1.getMasterKey());
assertArrayEquals(s1.getEphemeralPublicKey(), assertEquals(s1.getMasterKey(), s2.getMasterKey());
s2.getEphemeralPublicKey());
assertNull(s1.getEphemeralPrivateKey());
assertArrayEquals(s1.getEphemeralPrivateKey(),
s2.getEphemeralPrivateKey());
assertNull(s1.getTransportKeys()); assertNull(s1.getTransportKeys());
assertEquals(s1.getTransportKeys(), s2.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) @Test(expected = FormatException.class)
@@ -256,13 +308,15 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
} }
private IntroduceeSession getIntroduceeSession() { 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, return new IntroduceeSession(sessionId, LOCAL_ACCEPTED,
requestTimestamp, groupId1, lastLocalMessageId, localTimestamp, requestTimestamp, groupId1, author1, local, remote,
lastRemoteMessageId, author1, ephemeralPublicKey, masterKey, transportKeys);
ephemeralPrivateKey, transportProperties, acceptTimestamp,
masterKey, author2, remoteEphemeralPublicKey,
remoteTransportProperties, remoteAcceptTimestamp,
transportKeys);
} }
private void assertIntroduceeEquals(Introducee i1, Introducee i2) { private void assertIntroduceeEquals(Introducee i1, Introducee i2) {
@@ -273,9 +327,4 @@ public class SessionEncoderParserIntegrationTest extends BrambleTestCase {
assertEquals(i1.lastRemoteMessageId, i2.lastRemoteMessageId); assertEquals(i1.lastRemoteMessageId, i2.lastRemoteMessageId);
} }
private Author getRealAuthor() {
return authorFactory.createAuthor(getRandomString(5),
getRandomBytes(MAX_PUBLIC_KEY_LENGTH));
}
} }