Separate PINs from Registration Lock.

You can now have a PIN without having registration lock.

Note: We still need to change the registration flow to allow non-reglock
users to enter their PIN.
This commit is contained in:
Greyson Parrelli
2020-04-02 17:09:25 -04:00
parent 3c6a7b76ca
commit 8e13403cca
48 changed files with 905 additions and 523 deletions

View File

@@ -3,12 +3,12 @@ package org.whispersystems.signalservice.api;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.internal.contacts.entities.TokenResponse;
public final class RegistrationLockData {
public final class KbsPinData {
private final MasterKey masterKey;
private final TokenResponse tokenResponse;
RegistrationLockData(MasterKey masterKey, TokenResponse tokenResponse) {
KbsPinData(MasterKey masterKey, TokenResponse tokenResponse) {
this.masterKey = masterKey;
this.tokenResponse = tokenResponse;
}

View File

@@ -112,7 +112,7 @@ public final class KeyBackupService {
}
@Override
public RegistrationLockData restorePin(HashedPin hashedPin)
public KbsPinData restorePin(HashedPin hashedPin)
throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException
{
int attempt = 0;
@@ -145,7 +145,7 @@ public final class KeyBackupService {
}
}
private RegistrationLockData restorePin(HashedPin hashedPin, TokenResponse token)
private KbsPinData restorePin(HashedPin hashedPin, TokenResponse token)
throws UnauthenticatedResponseException, IOException, TokenException, KeyBackupSystemNoDataException
{
try {
@@ -165,7 +165,7 @@ public final class KeyBackupService {
Log.i(TAG, String.format(Locale.US,"Restore OK! data: %s tries: %d", Hex.toStringCondensed(status.getData().toByteArray()), status.getTries()));
KbsData kbsData = hashedPin.decryptKbsDataIVCipherText(status.getData().toByteArray());
MasterKey masterKey = kbsData.getMasterKey();
return new RegistrationLockData(masterKey, nextToken);
return new KbsPinData(masterKey, nextToken);
case PIN_MISMATCH:
Log.i(TAG, "Restore PIN_MISMATCH");
throw new KeyBackupServicePinException(nextToken);
@@ -199,24 +199,24 @@ public final class KeyBackupService {
}
@Override
public RegistrationLockData setPin(HashedPin hashedPin, MasterKey masterKey) throws IOException, UnauthenticatedResponseException {
KbsData newKbsData = hashedPin.createNewKbsData(masterKey);
public KbsPinData setPin(HashedPin hashedPin, MasterKey masterKey) throws IOException, UnauthenticatedResponseException {
KbsData newKbsData = hashedPin.createNewKbsData(masterKey);
TokenResponse tokenResponse = putKbsData(newKbsData.getKbsAccessKey(),
newKbsData.getCipherText(),
enclaveName,
currentToken);
pushServiceSocket.setRegistrationLock(masterKey.deriveRegistrationLock());
return new RegistrationLockData(masterKey, tokenResponse);
return new KbsPinData(masterKey, tokenResponse);
}
@Override
public void removePin() throws IOException, UnauthenticatedResponseException {
deleteKbsData();
public void enableRegistrationLock(MasterKey masterKey) throws IOException {
pushServiceSocket.setRegistrationLockV2(masterKey.deriveRegistrationLock());
}
pushServiceSocket.removePinV2();
@Override
public void disableRegistrationLock() throws IOException {
pushServiceSocket.disableRegistrationLockV2();
}
private TokenResponse putKbsData(byte[] kbsAccessKey, byte[] kbsData, String enclaveName, TokenResponse token)
@@ -243,20 +243,6 @@ public final class KeyBackupService {
throw new UnauthenticatedResponseException(e);
}
}
private void deleteKbsData()
throws IOException, UnauthenticatedResponseException
{
try {
RemoteAttestation remoteAttestation = getAndVerifyRemoteAttestation();
KeyBackupRequest request = KeyBackupCipher.createKeyDeleteRequest(currentToken, remoteAttestation, Hex.fromStringCondensed(enclaveName));
KeyBackupResponse response = pushServiceSocket.putKbsData(authorization, request, remoteAttestation.getCookies(), enclaveName);
KeyBackupCipher.getKeyDeleteResponseStatus(response, remoteAttestation);
} catch (InvalidCiphertextException e) {
throw new UnauthenticatedResponseException(e);
}
}
}
public interface HashSession {
@@ -266,16 +252,18 @@ public final class KeyBackupService {
public interface RestoreSession extends HashSession {
RegistrationLockData restorePin(HashedPin hashedPin)
KbsPinData restorePin(HashedPin hashedPin)
throws UnauthenticatedResponseException, IOException, KeyBackupServicePinException, KeyBackupSystemNoDataException;
}
public interface PinChangeSession extends HashSession {
/** Creates a PIN. Does nothing to registration lock. */
KbsPinData setPin(HashedPin hashedPin, MasterKey masterKey) throws IOException, UnauthenticatedResponseException;
RegistrationLockData setPin(HashedPin hashedPin, MasterKey masterKey)
throws IOException, UnauthenticatedResponseException;
/** Enables registration lock. This assumes a PIN is set. */
void enableRegistrationLock(MasterKey masterKey) throws IOException;
void removePin()
throws IOException, UnauthenticatedResponseException;
/** Disables registration lock. The user keeps their PIN. */
void disableRegistrationLock() throws IOException;
}
}

View File

@@ -10,7 +10,6 @@ package org.whispersystems.signalservice.api;
import com.google.protobuf.ByteString;
import org.signal.zkgroup.VerificationFailedException;
import org.signal.zkgroup.profiles.ClientZkProfileOperations;
import org.signal.zkgroup.profiles.ProfileKey;
import org.signal.zkgroup.profiles.ProfileKeyCredential;
import org.whispersystems.libsignal.IdentityKey;
@@ -29,6 +28,8 @@ import org.whispersystems.signalservice.api.groupsv2.ClientZkOperations;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Api;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Authorization;
import org.whispersystems.signalservice.api.groupsv2.GroupsV2Operations;
import org.whispersystems.signalservice.api.kbs.HashedPin;
import org.whispersystems.signalservice.api.kbs.MasterKey;
import org.whispersystems.signalservice.api.messages.calls.TurnServerInfo;
import org.whispersystems.signalservice.api.messages.multidevice.DeviceInfo;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
@@ -147,11 +148,14 @@ public class SignalServiceAccountManager {
}
/**
* V1 Pin setting has been replaced by KeyBackupService.
* Now you can only remove the old pin but there is no need to remove the old pin if setting a KBS Pin.
* V1 PINs are no longer used in favor of V2 PINs stored on KBS.
*
* You can remove a V1 PIN, but typically this is unnecessary, as setting a V2 PIN via
* {@link KeyBackupService.Session#enableRegistrationLock(MasterKey)}} will automatically clear the
* V1 PIN on the service.
*/
public void removeV1Pin() throws IOException {
this.pushServiceSocket.removePin();
public void removeRegistrationLockV1() throws IOException {
this.pushServiceSocket.removeRegistrationLockV1();
}
public UUID getOwnUuid() throws IOException {

View File

@@ -105,12 +105,16 @@ public class SignalServiceProfile {
@JsonProperty
private boolean gv2;
@JsonProperty
private boolean storage;
@JsonCreator
public Capabilities() {}
public Capabilities(boolean uuid, boolean gv2) {
this.uuid = uuid;
this.gv2 = gv2;
public Capabilities(boolean uuid, boolean gv2, boolean storage) {
this.uuid = uuid;
this.gv2 = gv2;
this.storage = storage;
}
public boolean isUuid() {
@@ -120,6 +124,10 @@ public class SignalServiceProfile {
public boolean isGv2() {
return gv2;
}
public boolean isStorage() {
return storage;
}
}
public ProfileKeyCredentialResponse getProfileKeyCredentialResponse() {

View File

@@ -41,7 +41,7 @@ public class SignalStorageManifest {
public Optional<StorageId> getAccountStorageId() {
List<StorageId> list = storageIdsByType.get(ManifestRecord.Identifier.Type.ACCOUNT_VALUE);
if (list.size() > 0) {
if (list != null && list.size() > 0) {
return Optional.of(list.get(0));
} else {
return Optional.absent();

View File

@@ -338,16 +338,16 @@ public class PushServiceSocket {
}
/** Note: Setting a KBS Pin will clear this */
public void removePin() throws IOException {
public void removeRegistrationLockV1() throws IOException {
makeServiceRequest(PIN_PATH, "DELETE", null);
}
public void setRegistrationLock(String registrationLock) throws IOException {
public void setRegistrationLockV2(String registrationLock) throws IOException {
RegistrationLockV2 accountLock = new RegistrationLockV2(registrationLock);
makeServiceRequest(REGISTRATION_LOCK_PATH, "PUT", JsonUtil.toJson(accountLock));
}
public void removePinV2() throws IOException {
public void disableRegistrationLockV2() throws IOException {
makeServiceRequest(REGISTRATION_LOCK_PATH, "DELETE", null);
}