Skip to content

Commit

Permalink
Better thread safety for session building <-> use.
Browse files Browse the repository at this point in the history
  • Loading branch information
moxie0 committed Oct 20, 2014
1 parent 7b1a37b commit 3e287f9
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -205,52 +205,53 @@ private int processV2(SessionRecord sessionRecord, PreKeyWhisperMessage message)
* trusted.
*/
public void process(PreKeyBundle preKey) throws InvalidKeyException, UntrustedIdentityException {
synchronized (SessionCipher.SESSION_LOCK) {
if (!identityKeyStore.isTrustedIdentity(recipientId, preKey.getIdentityKey())) {
throw new UntrustedIdentityException();
}

if (preKey.getSignedPreKey() != null &&
!Curve.verifySignature(preKey.getIdentityKey().getPublicKey(),
preKey.getSignedPreKey().serialize(),
preKey.getSignedPreKeySignature()))
{
throw new InvalidKeyException("Invalid signature on device key!");
}

if (preKey.getSignedPreKey() == null && preKey.getPreKey() == null) {
throw new InvalidKeyException("Both signed and unsigned prekeys are absent!");
}

SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
ECKeyPair ourBaseKey = Curve.generateKeyPair();
ECPublicKey theirSignedPreKey = preKey.getSignedPreKey() != null ? preKey.getSignedPreKey() :
preKey.getPreKey();

AliceAxolotlParameters.Builder parameters = AliceAxolotlParameters.newBuilder();

parameters.setOurBaseKey(ourBaseKey)
.setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
.setTheirIdentityKey(preKey.getIdentityKey())
.setTheirSignedPreKey(theirSignedPreKey)
.setTheirRatchetKey(theirSignedPreKey)
.setTheirOneTimePreKey(preKey.getSignedPreKey() != null ?
Optional.fromNullable(preKey.getPreKey()) :
Optional.<ECPublicKey>absent());

if (sessionRecord.getSessionState().getNeedsRefresh()) sessionRecord.archiveCurrentState();
else sessionRecord.reset();

RatchetingSession.initializeSession(sessionRecord.getSessionState(),
preKey.getSignedPreKey() == null ? 2 : 3,
parameters.create());

sessionRecord.getSessionState().setUnacknowledgedPreKeyMessage(preKey.getPreKeyId(), preKey.getSignedPreKeyId(), ourBaseKey.getPublicKey());
sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
sessionRecord.getSessionState().setRemoteRegistrationId(preKey.getRegistrationId());

if (!identityKeyStore.isTrustedIdentity(recipientId, preKey.getIdentityKey())) {
throw new UntrustedIdentityException();
}

if (preKey.getSignedPreKey() != null &&
!Curve.verifySignature(preKey.getIdentityKey().getPublicKey(),
preKey.getSignedPreKey().serialize(),
preKey.getSignedPreKeySignature()))
{
throw new InvalidKeyException("Invalid signature on device key!");
}

if (preKey.getSignedPreKey() == null && preKey.getPreKey() == null) {
throw new InvalidKeyException("Both signed and unsigned prekeys are absent!");
sessionStore.storeSession(recipientId, deviceId, sessionRecord);
identityKeyStore.saveIdentity(recipientId, preKey.getIdentityKey());
}

SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);
ECKeyPair ourBaseKey = Curve.generateKeyPair();
ECPublicKey theirSignedPreKey = preKey.getSignedPreKey() != null ? preKey.getSignedPreKey() :
preKey.getPreKey();

AliceAxolotlParameters.Builder parameters = AliceAxolotlParameters.newBuilder();

parameters.setOurBaseKey(ourBaseKey)
.setOurIdentityKey(identityKeyStore.getIdentityKeyPair())
.setTheirIdentityKey(preKey.getIdentityKey())
.setTheirSignedPreKey(theirSignedPreKey)
.setTheirRatchetKey(theirSignedPreKey)
.setTheirOneTimePreKey(preKey.getSignedPreKey() != null ?
Optional.fromNullable(preKey.getPreKey()) :
Optional.<ECPublicKey>absent());

if (sessionRecord.getSessionState().getNeedsRefresh()) sessionRecord.archiveCurrentState();
else sessionRecord.reset();

RatchetingSession.initializeSession(sessionRecord.getSessionState(),
preKey.getSignedPreKey() == null ? 2 : 3,
parameters.create());

sessionRecord.getSessionState().setUnacknowledgedPreKeyMessage(preKey.getPreKeyId(), preKey.getSignedPreKeyId(), ourBaseKey.getPublicKey());
sessionRecord.getSessionState().setLocalRegistrationId(identityKeyStore.getLocalRegistrationId());
sessionRecord.getSessionState().setRemoteRegistrationId(preKey.getRegistrationId());

sessionStore.storeSession(recipientId, deviceId, sessionRecord);
identityKeyStore.saveIdentity(recipientId, preKey.getIdentityKey());
}

/**
Expand All @@ -264,17 +265,18 @@ public void process(PreKeyBundle preKey) throws InvalidKeyException, UntrustedId
public KeyExchangeMessage process(KeyExchangeMessage message)
throws InvalidKeyException, UntrustedIdentityException, StaleKeyExchangeException
{
synchronized (SessionCipher.SESSION_LOCK) {
if (!identityKeyStore.isTrustedIdentity(recipientId, message.getIdentityKey())) {
throw new UntrustedIdentityException();
}

if (!identityKeyStore.isTrustedIdentity(recipientId, message.getIdentityKey())) {
throw new UntrustedIdentityException();
}

KeyExchangeMessage responseMessage = null;
KeyExchangeMessage responseMessage = null;

if (message.isInitiate()) responseMessage = processInitiate(message);
else processResponse(message);
if (message.isInitiate()) responseMessage = processInitiate(message);
else processResponse(message);

return responseMessage;
return responseMessage;
}
}

private KeyExchangeMessage processInitiate(KeyExchangeMessage message) throws InvalidKeyException {
Expand Down Expand Up @@ -375,22 +377,24 @@ private void processResponse(KeyExchangeMessage message)
* @return the KeyExchangeMessage to deliver.
*/
public KeyExchangeMessage process() {
try {
int sequence = KeyHelper.getRandomSequence(65534) + 1;
int flags = KeyExchangeMessage.INITIATE_FLAG;
ECKeyPair baseKey = Curve.generateKeyPair();
ECKeyPair ratchetKey = Curve.generateKeyPair();
IdentityKeyPair identityKey = identityKeyStore.getIdentityKeyPair();
byte[] baseKeySignature = Curve.calculateSignature(identityKey.getPrivateKey(), baseKey.getPublicKey().serialize());
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);

sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ratchetKey, identityKey);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);

return new KeyExchangeMessage(2, sequence, flags, baseKey.getPublicKey(), baseKeySignature,
ratchetKey.getPublicKey(), identityKey.getPublicKey());
} catch (InvalidKeyException e) {
throw new AssertionError(e);
synchronized (SessionCipher.SESSION_LOCK) {
try {
int sequence = KeyHelper.getRandomSequence(65534) + 1;
int flags = KeyExchangeMessage.INITIATE_FLAG;
ECKeyPair baseKey = Curve.generateKeyPair();
ECKeyPair ratchetKey = Curve.generateKeyPair();
IdentityKeyPair identityKey = identityKeyStore.getIdentityKeyPair();
byte[] baseKeySignature = Curve.calculateSignature(identityKey.getPrivateKey(), baseKey.getPublicKey().serialize());
SessionRecord sessionRecord = sessionStore.loadSession(recipientId, deviceId);

sessionRecord.getSessionState().setPendingKeyExchange(sequence, baseKey, ratchetKey, identityKey);
sessionStore.storeSession(recipientId, deviceId, sessionRecord);

return new KeyExchangeMessage(2, sequence, flags, baseKey.getPublicKey(), baseKeySignature,
ratchetKey.getPublicKey(), identityKey.getPublicKey());
} catch (InvalidKeyException e) {
throw new AssertionError(e);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
*/
public class SessionCipher {

private static final Object SESSION_LOCK = new Object();
public static final Object SESSION_LOCK = new Object();

private final SessionStore sessionStore;
private final SessionBuilder sessionBuilder;
Expand Down

0 comments on commit 3e287f9

Please sign in to comment.