|
|
|
@ -205,52 +205,53 @@ public class SessionBuilder {
|
|
|
|
|
* 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());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -264,17 +265,18 @@ public class SessionBuilder {
|
|
|
|
|
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 {
|
|
|
|
@ -375,22 +377,24 @@ public class SessionBuilder {
|
|
|
|
|
* @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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|