Add provisioning support for PNP.

This commit is contained in:
Greyson Parrelli
2022-02-02 18:35:16 -05:00
parent c2ca899a7c
commit dec1902dc7
23 changed files with 261 additions and 69 deletions

View File

@@ -19,6 +19,7 @@ import org.whispersystems.libsignal.logging.Log;
import org.whispersystems.libsignal.state.PreKeyRecord;
import org.whispersystems.libsignal.state.SignedPreKeyRecord;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.libsignal.util.guava.Preconditions;
import org.whispersystems.signalservice.api.account.AccountAttributes;
import org.whispersystems.signalservice.api.crypto.InvalidCiphertextException;
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
@@ -35,6 +36,7 @@ import org.whispersystems.signalservice.api.profiles.ProfileAndCredential;
import org.whispersystems.signalservice.api.profiles.SignalServiceProfileWrite;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.AccountIdentifier;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.push.SignedPreKeyEntity;
import org.whispersystems.signalservice.api.push.exceptions.NoContentException;
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
@@ -128,14 +130,16 @@ public class SignalServiceAccountManager {
/**
* Construct a SignalServiceAccountManager.
* @param configuration The URL for the Signal Service.
* @param aci The Signal Service UUID.
* @param configuration The URL for the Signal Service.
* @param aci The Signal Service ACI.
* @param pni The Signal Service PNI.
* @param e164 The Signal Service phone number.
* @param password A Signal Service password.
* @param signalAgent A string which identifies the client software.
*/
public SignalServiceAccountManager(SignalServiceConfiguration configuration,
ACI aci,
PNI pni,
String e164,
int deviceId,
String password,
@@ -143,7 +147,7 @@ public class SignalServiceAccountManager {
boolean automaticNetworkRetry)
{
this(configuration,
new StaticCredentialsProvider(aci, e164, deviceId, password),
new StaticCredentialsProvider(aci, pni, e164, deviceId, password),
signalAgent,
new GroupsV2Operations(ClientZkOperations.create(configuration)),
automaticNetworkRetry);
@@ -715,36 +719,32 @@ public class SignalServiceAccountManager {
public void addDevice(String deviceIdentifier,
ECPublicKey deviceKey,
IdentityKeyPair identityKeyPair,
Optional<byte[]> profileKey,
IdentityKeyPair aciIdentityKeyPair,
IdentityKeyPair pniIdentityKeyPair,
ProfileKey profileKey,
String code)
throws InvalidKeyException, IOException
{
PrimaryProvisioningCipher cipher = new PrimaryProvisioningCipher(deviceKey);
ProvisionMessage.Builder message = ProvisionMessage.newBuilder()
.setIdentityKeyPublic(ByteString.copyFrom(identityKeyPair.getPublicKey().serialize()))
.setIdentityKeyPrivate(ByteString.copyFrom(identityKeyPair.getPrivateKey().serialize()))
.setProvisioningCode(code)
.setProvisioningVersion(ProvisioningVersion.CURRENT_VALUE);
String e164 = credentials.getE164();
ACI aci = credentials.getAci();
PNI pni = credentials.getPni();
if (e164 != null) {
message.setNumber(e164);
} else {
throw new AssertionError("Missing phone number!");
}
Preconditions.checkArgument(e164 != null, "Missing e164!");
Preconditions.checkArgument(aci != null, "Missing ACI!");
Preconditions.checkArgument(pni != null, "Missing PNI!");
if (aci != null) {
message.setUuid(aci.toString());
} else {
Log.w(TAG, "[addDevice] Missing UUID.");
}
if (profileKey.isPresent()) {
message.setProfileKey(ByteString.copyFrom(profileKey.get()));
}
PrimaryProvisioningCipher cipher = new PrimaryProvisioningCipher(deviceKey);
ProvisionMessage.Builder message = ProvisionMessage.newBuilder()
.setAciIdentityKeyPublic(ByteString.copyFrom(aciIdentityKeyPair.getPublicKey().serialize()))
.setAciIdentityKeyPrivate(ByteString.copyFrom(aciIdentityKeyPair.getPrivateKey().serialize()))
.setPniIdentityKeyPublic(ByteString.copyFrom(pniIdentityKeyPair.getPublicKey().serialize()))
.setPniIdentityKeyPrivate(ByteString.copyFrom(pniIdentityKeyPair.getPrivateKey().serialize()))
.setAci(aci.toString())
.setPni(pni.toString())
.setNumber(e164)
.setProfileKey(ByteString.copyFrom(profileKey.serialize()))
.setProvisioningCode(code)
.setProvisioningVersion(ProvisioningVersion.CURRENT_VALUE);
byte[] ciphertext = cipher.encrypt(message.build());
this.pushServiceSocket.sendProvisioningMessage(deviceIdentifier, ciphertext);

View File

@@ -43,4 +43,8 @@ public class RequestMessage {
public boolean isKeysRequest() {
return request.getType() == Request.Type.KEYS;
}
public boolean isPniIdentityRequest() {
return request.getType() == Request.Type.PNI_IDENTITY;
}
}

View File

@@ -8,6 +8,7 @@ package org.whispersystems.signalservice.api.messages.multidevice;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.SignalServiceAttachment;
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.SyncMessage.PniIdentity;
import java.util.LinkedList;
import java.util.List;
@@ -28,6 +29,7 @@ public class SignalServiceSyncMessage {
private final Optional<KeysMessage> keys;
private final Optional<MessageRequestResponseMessage> messageRequestResponse;
private final Optional<OutgoingPaymentMessage> outgoingPaymentMessage;
private final Optional<PniIdentity> pniIdentity;
private final Optional<List<ViewedMessage>> views;
private SignalServiceSyncMessage(Optional<SentTranscriptMessage> sent,
@@ -44,7 +46,8 @@ public class SignalServiceSyncMessage {
Optional<KeysMessage> keys,
Optional<MessageRequestResponseMessage> messageRequestResponse,
Optional<OutgoingPaymentMessage> outgoingPaymentMessage,
Optional<List<ViewedMessage>> views)
Optional<List<ViewedMessage>> views,
Optional<PniIdentity> pniIdentity)
{
this.sent = sent;
this.contacts = contacts;
@@ -61,6 +64,7 @@ public class SignalServiceSyncMessage {
this.messageRequestResponse = messageRequestResponse;
this.outgoingPaymentMessage = outgoingPaymentMessage;
this.views = views;
this.pniIdentity = pniIdentity;
}
public static SignalServiceSyncMessage forSentTranscript(SentTranscriptMessage sent) {
@@ -78,6 +82,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -96,6 +101,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -114,6 +120,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -132,6 +139,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -150,6 +158,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -168,7 +177,8 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.of(views));
Optional.of(views),
Optional.absent());
}
public static SignalServiceSyncMessage forViewOnceOpen(ViewOnceOpenMessage timerRead) {
@@ -186,6 +196,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -207,6 +218,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -225,6 +237,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -243,6 +256,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -261,6 +275,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -279,6 +294,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -297,6 +313,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -315,6 +332,7 @@ public class SignalServiceSyncMessage {
Optional.of(keys),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -333,6 +351,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.of(messageRequestResponse),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -351,9 +370,29 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.of(outgoingPaymentMessage),
Optional.absent(),
Optional.absent());
}
public static SignalServiceSyncMessage forPniIdentity(PniIdentity pniIdentity) {
return new SignalServiceSyncMessage(Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.of(pniIdentity));
}
public static SignalServiceSyncMessage empty() {
return new SignalServiceSyncMessage(Optional.absent(),
Optional.absent(),
@@ -369,6 +408,7 @@ public class SignalServiceSyncMessage {
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent(),
Optional.absent());
}
@@ -432,6 +472,10 @@ public class SignalServiceSyncMessage {
return views;
}
public Optional<PniIdentity> getPniIdentity() {
return pniIdentity;
}
public enum FetchType {
LOCAL_PROFILE,
STORAGE_MANIFEST,

View File

@@ -7,9 +7,11 @@
package org.whispersystems.signalservice.api.util;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
public interface CredentialsProvider {
ACI getAci();
PNI getPni();
String getE164();
int getDeviceId();
String getPassword();

View File

@@ -7,17 +7,20 @@
package org.whispersystems.signalservice.internal.util;
import org.whispersystems.signalservice.api.push.ACI;
import org.whispersystems.signalservice.api.push.PNI;
import org.whispersystems.signalservice.api.util.CredentialsProvider;
public class StaticCredentialsProvider implements CredentialsProvider {
private final ACI aci;
private final PNI pni;
private final String e164;
private final int deviceId;
private final int deviceId;
private final String password;
public StaticCredentialsProvider(ACI aci, String e164, int deviceId, String password) {
public StaticCredentialsProvider(ACI aci, PNI pni, String e164, int deviceId, String password) {
this.aci = aci;
this.pni = pni;
this.e164 = e164;
this.deviceId = deviceId;
this.password = password;
@@ -28,6 +31,11 @@ public class StaticCredentialsProvider implements CredentialsProvider {
return aci;
}
@Override
public PNI getPni() {
return pni;
}
@Override
public String getE164() {
return e164;

View File

@@ -20,15 +20,19 @@ message ProvisionEnvelope {
}
message ProvisionMessage {
optional bytes identityKeyPublic = 1;
optional bytes identityKeyPrivate = 2;
optional string number = 3;
optional string uuid = 8;
optional string provisioningCode = 4;
optional string userAgent = 5;
optional bytes profileKey = 6;
optional bool readReceipts = 7;
optional uint32 provisioningVersion = 9;
optional bytes aciIdentityKeyPublic = 1;
optional bytes aciIdentityKeyPrivate = 2;
optional bytes pniIdentityKeyPublic = 11;
optional bytes pniIdentityKeyPrivate = 12;
optional string aci = 8;
optional string pni = 10;
optional string number = 3;
optional string provisioningCode = 4;
optional string userAgent = 5;
optional bytes profileKey = 6;
optional bool readReceipts = 7;
optional uint32 provisioningVersion = 9;
// NEXT ID: 13
}
enum ProvisioningVersion {

View File

@@ -26,12 +26,14 @@ message Envelope {
optional string sourceE164 = 2;
optional string sourceUuid = 11;
optional uint32 sourceDevice = 7;
optional string destinationUuid = 13;
optional string relay = 3;
optional uint64 timestamp = 5;
optional bytes legacyMessage = 6; // Contains an encrypted DataMessage
optional bytes content = 8; // Contains an encrypted Content
optional string serverGuid = 9;
optional uint64 serverTimestamp = 10;
// NEXT ID: 14
}
message Content {
@@ -408,6 +410,7 @@ message SyncMessage {
BLOCKED = 3;
CONFIGURATION = 4;
KEYS = 5;
PNI_IDENTITY = 6;
}
optional Type type = 1;
@@ -466,6 +469,11 @@ message SyncMessage {
optional bytes storageService = 1;
}
message PniIdentity {
optional bytes publicKey = 1;
optional bytes privateKey = 2;
}
message MessageRequestResponse {
enum Type {
UNKNOWN = 0;