Start increasing frequency of signed prekey rotation

// FREEBIE
This commit is contained in:
Moxie Marlinspike
2017-01-06 09:19:58 -08:00
parent 884d8b7f72
commit bb5dcb7131
19 changed files with 299 additions and 85 deletions

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.util.Log;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.PreKeyUtil;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.whispersystems.jobqueue.JobParameters;
@@ -11,7 +12,6 @@ import org.whispersystems.libsignal.InvalidKeyIdException;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyStore;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
@@ -30,7 +30,7 @@ public class CleanPreKeysJob extends MasterSecretJob implements InjectableType {
private static final String TAG = CleanPreKeysJob.class.getSimpleName();
private static final int ARCHIVE_AGE_DAYS = 15;
private static final long ARCHIVE_AGE = TimeUnit.DAYS.toMillis(7);
@Inject transient SignalServiceAccountManager accountManager;
@Inject transient SignedPreKeyStoreFactory signedPreKeyStoreFactory;
@@ -51,17 +51,20 @@ public class CleanPreKeysJob extends MasterSecretJob implements InjectableType {
@Override
public void onRun(MasterSecret masterSecret) throws IOException {
try {
SignedPreKeyStore signedPreKeyStore = signedPreKeyStoreFactory.create();
SignedPreKeyEntity currentSignedPreKey = accountManager.getSignedPreKey();
Log.w(TAG, "Cleaning prekeys...");
if (currentSignedPreKey == null) return;
int activeSignedPreKeyId = PreKeyUtil.getActiveSignedPreKeyId(context);
SignedPreKeyStore signedPreKeyStore = signedPreKeyStoreFactory.create();
SignedPreKeyRecord currentRecord = signedPreKeyStore.loadSignedPreKey(currentSignedPreKey.getKeyId());
if (activeSignedPreKeyId < 0) return;
SignedPreKeyRecord currentRecord = signedPreKeyStore.loadSignedPreKey(activeSignedPreKeyId);
List<SignedPreKeyRecord> allRecords = signedPreKeyStore.loadSignedPreKeys();
LinkedList<SignedPreKeyRecord> oldRecords = removeRecordFrom(currentRecord, allRecords);
Collections.sort(oldRecords, new SignedPreKeySorter());
Log.w(TAG, "Active signed prekey: " + activeSignedPreKeyId);
Log.w(TAG, "Old signed prekey record count: " + oldRecords.size());
boolean foundAgedRecord = false;
@@ -69,7 +72,7 @@ public class CleanPreKeysJob extends MasterSecretJob implements InjectableType {
for (SignedPreKeyRecord oldRecord : oldRecords) {
long archiveDuration = System.currentTimeMillis() - oldRecord.getTimestamp();
if (archiveDuration >= TimeUnit.DAYS.toMillis(ARCHIVE_AGE_DAYS)) {
if (archiveDuration >= ARCHIVE_AGE) {
if (!foundAgedRecord) {
foundAgedRecord = true;
} else {

View File

@@ -53,7 +53,7 @@ public class CreateSignedPreKeyJob extends MasterSecretJob implements Injectable
}
IdentityKeyPair identityKeyPair = IdentityKeyUtil.getIdentityKeyPair(context);
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, identityKeyPair);
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, identityKeyPair, true);
accountManager.setSignedPreKey(signedPreKeyRecord);
TextSecurePreferences.setSignedPreKeyRegistered(context, true);

View File

@@ -70,12 +70,10 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
@Override
public void onAdded() {
// DatabaseFactory.getMmsDatabase(context)
// .markAsSending(messageId);
}
@Override
public void onSend(MasterSecret masterSecret)
public void onPushSend(MasterSecret masterSecret)
throws MmsException, IOException, NoSuchMessageException
{
MmsDatabase database = DatabaseFactory.getMmsDatabase(context);
@@ -84,8 +82,6 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
try {
deliver(masterSecret, message, filterRecipientId);
// database.markAsPush(messageId);
// database.markAsSecure(messageId);
database.markAsSent(messageId, true);
markAttachmentsUploaded(messageId, message.getAttachments());
@@ -114,10 +110,8 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
}
database.addFailures(messageId, failures);
// database.markAsPush(messageId);
if (e.getNetworkExceptions().isEmpty() && e.getUntrustedIdentityExceptions().isEmpty()) {
// database.markAsSecure(messageId);
database.markAsSent(messageId, true);
markAttachmentsUploaded(messageId, message.getAttachments());
} else {

View File

@@ -53,13 +53,11 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
@Override
public void onAdded() {
// MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
// mmsDatabase.markAsSending(messageId);
// mmsDatabase.markAsPush(messageId);
}
@Override
public void onSend(MasterSecret masterSecret)
public void onPushSend(MasterSecret masterSecret)
throws RetryLaterException, MmsException, NoSuchMessageException,
UndeliverableMessageException
{
@@ -69,8 +67,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
try {
deliver(masterSecret, message);
// database.markAsPush(messageId);
// database.markAsSecure(messageId);
database.markAsSent(messageId, true);
markAttachmentsUploaded(messageId, message.getAttachments());
@@ -91,7 +87,6 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
database.addMismatchedIdentity(messageId, recipientId, uie.getIdentityKey());
database.markAsSentFailed(messageId);
// database.markAsPush(messageId);
}
}

View File

@@ -3,6 +3,8 @@ package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.util.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.TextSecureExpiredException;
import org.thoughtcrime.securesms.attachments.Attachment;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.database.DatabaseFactory;
@@ -12,6 +14,7 @@ import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.notifications.MessageNotifier;
import org.thoughtcrime.securesms.recipients.Recipients;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
@@ -48,6 +51,19 @@ public abstract class PushSendJob extends SendJob {
return builder.create();
}
@Override
protected final void onSend(MasterSecret masterSecret) throws Exception {
if (TextSecurePreferences.getSignedPreKeyFailureCount(context) > 5) {
ApplicationContext.getInstance(context)
.getJobManager()
.add(new RotateSignedPreKeyJob(context));
throw new TextSecureExpiredException("Too many signed prekey rotation failures");
}
onPushSend(masterSecret);
}
protected SignalServiceAddress getPushAddress(String number) throws InvalidNumberException {
String e164number = Util.canonicalizeNumber(context, number);
String relay = TextSecureDirectory.getInstance(context).getRelay(e164number);
@@ -93,4 +109,6 @@ public abstract class PushSendJob extends SendJob {
MessageNotifier.notifyMessageDeliveryFailed(context, recipients, threadId);
}
}
protected abstract void onPushSend(MasterSecret masterSecret) throws Exception;
}

View File

@@ -49,7 +49,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
public void onAdded() {}
@Override
public void onSend(MasterSecret masterSecret) throws NoSuchMessageException, RetryLaterException {
public void onPushSend(MasterSecret masterSecret) throws NoSuchMessageException, RetryLaterException {
ExpiringMessageManager expirationManager = ApplicationContext.getInstance(context).getExpiringMessageManager();
EncryptingSmsDatabase database = DatabaseFactory.getEncryptingSmsDatabase(context);
SmsMessageRecord record = database.getMessage(masterSecret, messageId);

View File

@@ -60,12 +60,13 @@ public class RefreshPreKeysJob extends MasterSecretJob implements InjectableType
List<PreKeyRecord> preKeyRecords = PreKeyUtil.generatePreKeys(context);
PreKeyRecord lastResortKeyRecord = PreKeyUtil.generateLastResortKey(context);
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context);
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, identityKey);
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, identityKey, false);
Log.w(TAG, "Registering new prekeys...");
accountManager.setPreKeys(identityKey.getPublicKey(), lastResortKeyRecord, signedPreKeyRecord, preKeyRecords);
PreKeyUtil.setActiveSignedPreKeyId(context, signedPreKeyRecord.getId());
TextSecurePreferences.setSignedPreKeyRegistered(context, true);
ApplicationContext.getInstance(context)

View File

@@ -0,0 +1,69 @@
package org.thoughtcrime.securesms.jobs;
import android.content.Context;
import android.util.Log;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
import org.thoughtcrime.securesms.crypto.MasterSecret;
import org.thoughtcrime.securesms.crypto.PreKeyUtil;
import org.thoughtcrime.securesms.dependencies.InjectableType;
import org.thoughtcrime.securesms.jobs.requirements.MasterSecretRequirement;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.whispersystems.jobqueue.JobParameters;
import org.whispersystems.jobqueue.requirements.NetworkRequirement;
import org.whispersystems.libsignal.IdentityKeyPair;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
import javax.inject.Inject;
public class RotateSignedPreKeyJob extends MasterSecretJob implements InjectableType {
private static final String TAG = RotateSignedPreKeyJob.class.getName();
@Inject transient SignalServiceAccountManager accountManager;
public RotateSignedPreKeyJob(Context context) {
super(context, JobParameters.newBuilder()
.withRequirement(new NetworkRequirement(context))
.withRequirement(new MasterSecretRequirement(context))
.withRetryCount(5)
.create());
}
@Override
public void onAdded() {
}
@Override
public void onRun(MasterSecret masterSecret) throws Exception {
Log.w(TAG, "Rotating signed prekey...");
IdentityKeyPair identityKey = IdentityKeyUtil.getIdentityKeyPair(context);
SignedPreKeyRecord signedPreKeyRecord = PreKeyUtil.generateSignedPreKey(context, identityKey, false);
accountManager.setSignedPreKey(signedPreKeyRecord);
PreKeyUtil.setActiveSignedPreKeyId(context, signedPreKeyRecord.getId());
TextSecurePreferences.setSignedPreKeyRegistered(context, true);
TextSecurePreferences.setSignedPreKeyFailureCount(context, 0);
ApplicationContext.getInstance(context)
.getJobManager()
.add(new CleanPreKeysJob(context));
}
@Override
public boolean onShouldRetryThrowable(Exception exception) {
return exception instanceof PushNetworkException;
}
@Override
public void onCanceled() {
TextSecurePreferences.setSignedPreKeyFailureCount(context, TextSecurePreferences.getSignedPreKeyFailureCount(context) + 1);
}
}