Commit e1fae7ad authored by Torsten Grote's avatar Torsten Grote

Implement SessionEncoder and SessionParser

parent 672a52b2
package org.briarproject.briar.api.introduction2;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public enum Role {
INTRODUCER(0), INTRODUCEE(1);
private final int value;
Role(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static Role fromValue(int value) throws FormatException {
for (Role r : values()) if (r.value == value) return r;
throw new FormatException();
}
}
package org.briarproject.briar.introduction2;
import org.briarproject.bramble.api.crypto.SecretKey;
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.properties.TransportProperties;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
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.introduction2.Role;
import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.briar.introduction2.IntroduceeState.AWAIT_ACTIVATE;
import static org.briarproject.briar.introduction2.IntroduceeState.START;
import static org.briarproject.briar.api.introduction2.Role.INTRODUCEE;
@Immutable
@NotNullByDefault
class IntroduceeSession extends Session<IntroduceeState>
implements PeerSession {
private final GroupId contactGroupId;
private final long localTimestamp, acceptTimestamp, remoteAcceptTimestamp;
@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;
@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,
@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.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);
}
static IntroduceeSession addRemoteRequest(IntroduceeSession s,
IntroduceeState state, RequestMessage m) {
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.transportKeys);
}
static IntroduceeSession addLocalAccept(IntroduceeSession s,
IntroduceeState state, Message acceptMessage,
byte[] ephemeralPublicKey, byte[] ephemeralPrivateKey,
long acceptTimestamp,
Map<TransportId, TransportProperties> transportProperties) {
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);
}
static IntroduceeSession addRemoteAccept(IntroduceeSession s,
IntroduceeState state, AcceptMessage acceptMessage) {
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);
}
static IntroduceeSession addLocalAuth(IntroduceeSession s,
IntroduceeState state, SecretKey masterKey, Message m) {
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);
}
static IntroduceeSession awaitActivate(IntroduceeSession s, AuthMessage m,
Message sent, Map<TransportId, KeySetId> transportKeys) {
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);
}
static IntroduceeSession clear(IntroduceeSession s,
@Nullable MessageId lastLocalMessageId, long localTimestamp,
@Nullable MessageId lastRemoteMessageId) {
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);
}
@Override
Role getRole() {
return INTRODUCEE;
}
public GroupId getContactGroupId() {
return contactGroupId;
}
public long getLocalTimestamp() {
return localTimestamp;
}
@Nullable
public MessageId getLastLocalMessageId() {
return lastLocalMessageId;
}
@Nullable
public MessageId getLastRemoteMessageId() {
return lastRemoteMessageId;
}
Author getIntroducer() {
return introducer;
}
@Nullable
byte[] getEphemeralPublicKey() {
return ephemeralPublicKey;
}
@Nullable
byte[] getEphemeralPrivateKey() {
return ephemeralPrivateKey;
}
@Nullable
Map<TransportId, TransportProperties> getTransportProperties() {
return transportProperties;
}
long getAcceptTimestamp() {
return acceptTimestamp;
}
@Nullable
byte[] getMasterKey() {
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;
}
}
package org.briarproject.briar.introduction2;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
enum IntroduceeState implements State {
START(0),
AWAIT_RESPONSES(1),
LOCAL_DECLINED(2),
LOCAL_ACCEPTED(3),
REMOTE_ACCEPTED(4),
AWAIT_AUTH(5),
AWAIT_ACTIVATE(6);
private final int value;
IntroduceeState(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
static IntroduceeState fromValue(int value) throws FormatException {
for (IntroduceeState s : values()) if (s.value == value) return s;
throw new FormatException();
}
}
package org.briarproject.briar.introduction2;
import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.introduction2.Role;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import static org.briarproject.briar.api.introduction2.Role.INTRODUCER;
@Immutable
@NotNullByDefault
class IntroducerSession extends Session<IntroducerState> {
private final Introducee introducee1, introducee2;
IntroducerSession(SessionId sessionId, IntroducerState state,
long requestTimestamp, Introducee introducee1,
Introducee introducee2) {
super(sessionId, state, requestTimestamp);
this.introducee1 = introducee1;
this.introducee2 = introducee2;
}
IntroducerSession(SessionId sessionId, GroupId groupId1, Author author1,
GroupId groupId2, Author author2) {
this(sessionId, IntroducerState.START, -1,
new Introducee(sessionId, groupId1, author1),
new Introducee(sessionId, groupId2, author2));
}
@Override
Role getRole() {
return INTRODUCER;
}
Introducee getIntroducee1() {
return introducee1;
}
Introducee getIntroducee2() {
return introducee2;
}
@Immutable
@NotNullByDefault
static class Introducee implements PeerSession {
final SessionId sessionId;
final GroupId groupId;
final Author author;
final long localTimestamp;
@Nullable
final MessageId lastLocalMessageId, lastRemoteMessageId;
Introducee(SessionId sessionId, GroupId groupId, Author author,
long localTimestamp,
@Nullable MessageId lastLocalMessageId,
@Nullable MessageId lastRemoteMessageId) {
this.sessionId = sessionId;
this.groupId = groupId;
this.localTimestamp = localTimestamp;
this.author = author;
this.lastLocalMessageId = lastLocalMessageId;
this.lastRemoteMessageId = lastRemoteMessageId;
}
Introducee(Introducee i, Message sent) {
this(i.sessionId, i.groupId, i.author, sent.getTimestamp(),
sent.getId(), i.lastRemoteMessageId);
}
Introducee(Introducee i, MessageId remoteMessageId) {
this(i.sessionId, i.groupId, i.author, i.localTimestamp,
i.lastLocalMessageId, remoteMessageId);
}
private Introducee(SessionId sessionId, GroupId groupId,
Author author) {
this(sessionId, groupId, author, -1, null, null);
}
public SessionId getSessionId() {
return sessionId;
}
@Override
public GroupId getContactGroupId() {
return groupId;
}
@Override
public long getLocalTimestamp() {
return localTimestamp;
}
@Nullable
@Override
public MessageId getLastLocalMessageId() {
return lastLocalMessageId;
}
@Nullable
@Override
public MessageId getLastRemoteMessageId() {
return lastRemoteMessageId;
}
}
}
package org.briarproject.briar.introduction2;
import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
enum IntroducerState implements State {
START(0),
AWAIT_RESPONSES(1),
AWAIT_RESPONSE_A(2), AWAIT_RESPONSE_B(3),
AWAIT_AUTHS(4),
AWAIT_AUTH_A(5), AWAIT_AUTH_B(6),
AWAIT_ACTIVATES(7),
AWAIT_ACTIVATE_A(8), AWAIT_ACTIVATE_B(9);
private final int value;
IntroducerState(int value) {
this.value = value;
}
@Override
public int getValue() {
return value;
}
static IntroducerState fromValue(int value) throws FormatException {
for (IntroducerState s : values()) if (s.value == value) return s;
throw new FormatException();
}
}
......@@ -11,4 +11,33 @@ interface IntroductionConstants {
String MSG_KEY_AVAILABLE_TO_ANSWER = "availableToAnswer";
String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
// Session Keys
String SESSION_KEY_SESSION_ID = "sessionId";
String SESSION_KEY_ROLE = "role";
String SESSION_KEY_STATE = "state";
String SESSION_KEY_REQUEST_TIMESTAMP = "requestTimestamp";
String SESSION_KEY_LOCAL_TIMESTAMP = "localTimestamp";
String SESSION_KEY_LAST_LOCAL_MESSAGE_ID = "lastLocalMessageId";
String SESSION_KEY_LAST_REMOTE_MESSAGE_ID = "lastRemoteMessageId";
// Session Keys Introducer
String SESSION_KEY_INTRODUCEE_1 = "introducee1";
String SESSION_KEY_INTRODUCEE_2 = "introducee2";
String SESSION_KEY_GROUP_ID = "groupId";
String SESSION_KEY_AUTHOR = "author";
// Session Keys Introducee
String SESSION_KEY_INTRODUCER = "introducer";
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_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";
}
package org.briarproject.briar.introduction2;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.GroupId;
import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.briar.api.client.SessionId;
import javax.annotation.Nullable;
@NotNullByDefault
interface PeerSession {
SessionId getSessionId();
GroupId getContactGroupId();
long getLocalTimestamp();
@Nullable
MessageId getLastLocalMessageId();
@Nullable
MessageId getLastRemoteMessageId();
}
package org.briarproject.briar.introduction2;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.introduction2.Role;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
abstract class Session<S extends State> {
private final SessionId sessionId;
private final S state;
private long requestTimestamp;
Session(SessionId sessionId, S state, long requestTimestamp) {
this.sessionId = sessionId;
this.state = state;
this.requestTimestamp = requestTimestamp;
}
abstract Role getRole();
public SessionId getSessionId() {
return sessionId;
}
S getState() {
return state;
}
public long getRequestTimestamp() {
return requestTimestamp;
}
}
package org.briarproject.briar.introduction2;
import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@NotNullByDefault
interface SessionEncoder {
BdfDictionary encodeIntroducerSession(IntroducerSession s);
BdfDictionary encodeIntroduceeSession(IntroduceeSession s);
}
package org.briarproject.briar.introduction2;
import org.briarproject.bramble.api.client.ClientHelper;
import org.briarproject.bramble.api.data.BdfDictionary;
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.introduction2.IntroducerSession.Introducee;
import java.util.Map;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_ACCEPT_TIMESTAMP;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_AUTHOR;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_EPHEMERAL_PRIVATE_KEY;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_EPHEMERAL_PUBLIC_KEY;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_GROUP_ID;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCEE_1;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCEE_2;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_INTRODUCER;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_LOCAL_TIMESTAMP;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_MASTER_KEY;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_ACCEPT_TIMESTAMP;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_AUTHOR;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_EPHEMERAL_PUBLIC_KEY;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REMOTE_TRANSPORT_PROPERTIES;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_REQUEST_TIMESTAMP;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_ROLE;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_SESSION_ID;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_STATE;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_TRANSPORT_KEYS;
import static org.briarproject.briar.introduction2.IntroductionConstants.SESSION_KEY_TRANSPORT_PROPERTIES;
@Immutable
@NotNullByDefault
class SessionEncoderImpl implements SessionEncoder {
private final ClientHelper clientHelper;
@Inject
SessionEncoderImpl(ClientHelper clientHelper) {
this.clientHelper = clientHelper;
}
@Override
public BdfDictionary encodeIntroducerSession(IntroducerSession s) {
BdfDictionary d = encodeSession(s);
d.put(SESSION_KEY_INTRODUCEE_1, encodeIntroducee(s.getIntroducee1()));
d.put(SESSION_KEY_INTRODUCEE_2, encodeIntroducee(s.getIntroducee2()));
return d;
}
private BdfDictionary encodeIntroducee(Introducee i) {
BdfDictionary d = new BdfDictionary();
putNullable(d, SESSION_KEY_LAST_LOCAL_MESSAGE_ID, i.lastLocalMessageId);
putNullable(d, SESSION_KEY_LAST_REMOTE_MESSAGE_ID,
i.lastRemoteMessageId);
d.put(SESSION_KEY_LOCAL_TIMESTAMP, i.localTimestamp);
d.put(SESSION_KEY_GROUP_ID, i.groupId);
d.put(SESSION_KEY_AUTHOR, clientHelper.toList(i.author));
return d;
}
@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());
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()));