mirror of
https://github.com/signalapp/Signal-Server
synced 2026-04-21 03:48:05 +01:00
PQXDH endpoints for chat server
This commit is contained in:
committed by
GitHub
parent
34d77e73ff
commit
caae27c44c
@@ -7,6 +7,8 @@ package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -16,21 +18,57 @@ import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
|
||||
public record ChangeNumberRequest(String sessionId,
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) byte[] recoveryPassword,
|
||||
@NotBlank String number,
|
||||
@JsonProperty("reglock") @Nullable String registrationLock,
|
||||
@NotBlank String pniIdentityKey,
|
||||
@NotNull @Valid List<@NotNull @Valid IncomingMessage> deviceMessages,
|
||||
@NotNull @Valid Map<Long, @NotNull @Valid SignedPreKey> devicePniSignedPrekeys,
|
||||
@NotNull Map<Long, Integer> pniRegistrationIds) implements PhoneVerificationRequest {
|
||||
public record ChangeNumberRequest(
|
||||
@Schema(description="""
|
||||
A session ID from registration service, if using session id to authenticate this request.
|
||||
Must not be combined with `recoveryPassword`.""")
|
||||
String sessionId,
|
||||
|
||||
@Schema(description="""
|
||||
The recovery password for the new phone number, if using a recovery password to authenticate this request.
|
||||
Must not be combined with `sessionId`.""")
|
||||
@JsonDeserialize(using = ByteArrayAdapter.Deserializing.class) byte[] recoveryPassword,
|
||||
|
||||
@Schema(description="the new phone number for this account")
|
||||
@NotBlank String number,
|
||||
|
||||
@Schema(description="the registration lock password for the new phone number, if necessary")
|
||||
@JsonProperty("reglock") @Nullable String registrationLock,
|
||||
|
||||
@Schema(description="the new public identity key to use for the phone-number identity associated with the new phone number")
|
||||
@NotBlank String pniIdentityKey,
|
||||
|
||||
@Schema(description="""
|
||||
A list of synchronization messages to send to companion devices to supply the private keys
|
||||
associated with the new identity key and their new prekeys.
|
||||
Exactly one message must be supplied for each enabled device other than the sending (primary) device.""")
|
||||
@NotNull @Valid List<@NotNull @Valid IncomingMessage> deviceMessages,
|
||||
|
||||
@Schema(description="""
|
||||
A new signed elliptic-curve prekey for each enabled device on the account, including this one.
|
||||
Each must be accompanied by a valid signature from the new identity key in this request.""")
|
||||
@NotNull @Valid Map<Long, @NotNull @Valid SignedPreKey> devicePniSignedPrekeys,
|
||||
|
||||
@Schema(description="""
|
||||
A new signed post-quantum last-resort prekey for each enabled device on the account, including this one.
|
||||
May be absent, in which case the last resort PQ prekeys for each device will be deleted if any had been stored.
|
||||
If present, must contain one prekey per enabled device including this one.
|
||||
Prekeys for devices that did not previously have any post-quantum prekeys stored will be silently dropped.
|
||||
Each must be accompanied by a valid signature from the new identity key in this request.""")
|
||||
@Valid Map<Long, @NotNull @Valid SignedPreKey> devicePniPqLastResortPrekeys,
|
||||
|
||||
@Schema(description="the new phone-number-identity registration ID for each enabled device on the account, including this one")
|
||||
@NotNull Map<Long, Integer> pniRegistrationIds) implements PhoneVerificationRequest {
|
||||
|
||||
@AssertTrue
|
||||
public boolean isSignatureValidOnEachSignedPreKey() {
|
||||
if (devicePniSignedPrekeys == null) {
|
||||
return true;
|
||||
List<SignedPreKey> spks = new ArrayList<>();
|
||||
if (devicePniSignedPrekeys != null) {
|
||||
spks.addAll(devicePniSignedPrekeys.values());
|
||||
}
|
||||
return devicePniSignedPrekeys.values().parallelStream()
|
||||
.allMatch(spk -> PreKeySignatureValidator.validatePreKeySignature(pniIdentityKey, spk));
|
||||
if (devicePniPqLastResortPrekeys != null) {
|
||||
spks.addAll(devicePniPqLastResortPrekeys.values());
|
||||
}
|
||||
return spks.isEmpty() || PreKeySignatureValidator.validatePreKeySignatures(pniIdentityKey, spks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,27 +6,61 @@
|
||||
package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
public record ChangePhoneNumberRequest(@NotBlank String number,
|
||||
@NotBlank String code,
|
||||
@JsonProperty("reglock") @Nullable String registrationLock,
|
||||
@Nullable String pniIdentityKey,
|
||||
@Nullable List<IncomingMessage> deviceMessages,
|
||||
@Nullable Map<Long, SignedPreKey> devicePniSignedPrekeys,
|
||||
@Nullable Map<Long, Integer> pniRegistrationIds) {
|
||||
public record ChangePhoneNumberRequest(
|
||||
@Schema(description="the new phone number for this account")
|
||||
@NotBlank String number,
|
||||
|
||||
@Schema(description="the registration verification code to authenticate this request")
|
||||
@NotBlank String code,
|
||||
|
||||
@Schema(description="the registration lock password for the new phone number, if necessary")
|
||||
@JsonProperty("reglock") @Nullable String registrationLock,
|
||||
|
||||
@Schema(description="the new public identity key to use for the phone-number identity associated with the new phone number")
|
||||
@Nullable String pniIdentityKey,
|
||||
|
||||
@Schema(description="""
|
||||
A list of synchronization messages to send to companion devices to supply the private keys
|
||||
associated with the new identity key and their new prekeys.
|
||||
Exactly one message must be supplied for each enabled device other than the sending (primary) device.""")
|
||||
@Nullable List<IncomingMessage> deviceMessages,
|
||||
|
||||
@Schema(description="""
|
||||
A new signed elliptic-curve prekey for each enabled device on the account, including this one.
|
||||
Each must be accompanied by a valid signature from the new identity key in this request.""")
|
||||
@Nullable Map<Long, SignedPreKey> devicePniSignedPrekeys,
|
||||
|
||||
@Schema(description="""
|
||||
A new signed post-quantum last-resort prekey for each enabled device on the account, including this one.
|
||||
May be absent, in which case the last resort PQ prekeys for each device will be deleted if any had been stored.
|
||||
If present, must contain one prekey per enabled device including this one.
|
||||
Prekeys for devices that did not previously have any post-quantum prekeys stored will be silently dropped.
|
||||
Each must be accompanied by a valid signature from the new identity key in this request.""")
|
||||
@Nullable @Valid Map<Long, @NotNull @Valid SignedPreKey> devicePniPqLastResortPrekeys,
|
||||
|
||||
@Schema(description="the new phone-number-identity registration ID for each enabled device on the account, including this one")
|
||||
@Nullable Map<Long, Integer> pniRegistrationIds) {
|
||||
|
||||
@AssertTrue
|
||||
public boolean isSignatureValidOnEachSignedPreKey() {
|
||||
if (devicePniSignedPrekeys == null) {
|
||||
return true;
|
||||
List<SignedPreKey> spks = new ArrayList<>();
|
||||
if (devicePniSignedPrekeys != null) {
|
||||
spks.addAll(devicePniSignedPrekeys.values());
|
||||
}
|
||||
return devicePniSignedPrekeys.values().parallelStream()
|
||||
.allMatch(spk -> PreKeySignatureValidator.validatePreKeySignature(pniIdentityKey, spk));
|
||||
if (devicePniPqLastResortPrekeys != null) {
|
||||
spks.addAll(devicePniPqLastResortPrekeys.values());
|
||||
}
|
||||
return spks.isEmpty() || PreKeySignatureValidator.validatePreKeySignatures(pniIdentityKey, spks);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
@@ -17,29 +18,45 @@ import javax.validation.constraints.NotNull;
|
||||
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
|
||||
|
||||
public record PhoneNumberIdentityKeyDistributionRequest(
|
||||
@NotBlank
|
||||
@Schema(description="the new identity key for this account's phone-number identity")
|
||||
String pniIdentityKey,
|
||||
@NotBlank
|
||||
@Schema(description="the new identity key for this account's phone-number identity")
|
||||
String pniIdentityKey,
|
||||
|
||||
@NotNull
|
||||
@Valid
|
||||
@Schema(description="A message for each companion device to pass its new private keys")
|
||||
List<@NotNull @Valid IncomingMessage> deviceMessages,
|
||||
@NotNull
|
||||
@Valid
|
||||
@Schema(description="""
|
||||
A list of synchronization messages to send to companion devices to supply the private keys
|
||||
associated with the new identity key and their new prekeys.
|
||||
Exactly one message must be supplied for each enabled device other than the sending (primary) device.""")
|
||||
List<@NotNull @Valid IncomingMessage> deviceMessages,
|
||||
|
||||
@NotNull
|
||||
@Valid
|
||||
@Schema(description="The public key of a new signed elliptic-curve prekey pair for each device")
|
||||
Map<Long, @NotNull @Valid SignedPreKey> devicePniSignedPrekeys,
|
||||
@NotNull
|
||||
@Valid
|
||||
@Schema(description="""
|
||||
A new signed elliptic-curve prekey for each enabled device on the account, including this one.
|
||||
Each must be accompanied by a valid signature from the new identity key in this request.""")
|
||||
Map<Long, @NotNull @Valid SignedPreKey> devicePniSignedPrekeys,
|
||||
|
||||
@NotNull
|
||||
@Valid
|
||||
@Schema(description="The new registration ID to use for the phone-number identity of each device")
|
||||
Map<Long, Integer> pniRegistrationIds) {
|
||||
@Schema(description="""
|
||||
A new signed post-quantum last-resort prekey for each enabled device on the account, including this one.
|
||||
May be absent, in which case the last resort PQ prekeys for each device will be deleted if any had been stored.
|
||||
If present, must contain one prekey per enabled device including this one.
|
||||
Prekeys for devices that did not previously have any post-quantum prekeys stored will be silently dropped.
|
||||
Each must be accompanied by a valid signature from the new identity key in this request.""")
|
||||
@Valid Map<Long, @NotNull @Valid SignedPreKey> devicePniPqLastResortPrekeys,
|
||||
|
||||
@NotNull
|
||||
@Valid
|
||||
@Schema(description="The new registration ID to use for the phone-number identity of each device")
|
||||
Map<Long, Integer> pniRegistrationIds) {
|
||||
|
||||
@AssertTrue
|
||||
public boolean isSignatureValidOnEachSignedPreKey() {
|
||||
return devicePniSignedPrekeys.values().parallelStream()
|
||||
.allMatch(spk -> PreKeySignatureValidator.validatePreKeySignature(pniIdentityKey, spk));
|
||||
List<SignedPreKey> spks = new ArrayList<>(devicePniSignedPrekeys.values());
|
||||
if (devicePniPqLastResortPrekeys != null) {
|
||||
spks.addAll(devicePniPqLastResortPrekeys.values());
|
||||
}
|
||||
return spks.isEmpty() || PreKeySignatureValidator.validatePreKeySignatures(pniIdentityKey, spks);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,17 +13,17 @@ public class PreKey {
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
private long keyId;
|
||||
private long keyId;
|
||||
|
||||
@JsonProperty
|
||||
@NotEmpty
|
||||
private String publicKey;
|
||||
private String publicKey;
|
||||
|
||||
public PreKey() {}
|
||||
|
||||
public PreKey(long keyId, String publicKey)
|
||||
{
|
||||
this.keyId = keyId;
|
||||
this.keyId = keyId;
|
||||
this.publicKey = publicKey;
|
||||
}
|
||||
|
||||
@@ -63,5 +63,4 @@ public class PreKey {
|
||||
return ((int)this.keyId) ^ publicKey.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,16 +5,22 @@
|
||||
|
||||
package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
public class PreKeyCount {
|
||||
|
||||
@Schema(description="the number of stored unsigned elliptic-curve prekeys for this device")
|
||||
@JsonProperty
|
||||
private int count;
|
||||
|
||||
public PreKeyCount(int count) {
|
||||
this.count = count;
|
||||
@Schema(description="the number of stored one-time post-quantum prekeys for this device")
|
||||
@JsonProperty
|
||||
private int pqCount;
|
||||
|
||||
public PreKeyCount(int ecCount, int pqCount) {
|
||||
this.count = ecCount;
|
||||
this.pqCount = pqCount;
|
||||
}
|
||||
|
||||
public PreKeyCount() {}
|
||||
@@ -22,4 +28,8 @@ public class PreKeyCount {
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
public int getPqCount() {
|
||||
return pqCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,15 +7,18 @@ package org.whispersystems.textsecuregcm.entities;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PreKeyResponse {
|
||||
|
||||
@JsonProperty
|
||||
@Schema(description="the public identity key for the requested identity")
|
||||
private String identityKey;
|
||||
|
||||
@JsonProperty
|
||||
@Schema(description="information about each requested device")
|
||||
private List<PreKeyResponseItem> devices;
|
||||
|
||||
public PreKeyResponse() {}
|
||||
|
||||
@@ -6,28 +6,39 @@ package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
public class PreKeyResponseItem {
|
||||
|
||||
@JsonProperty
|
||||
@Schema(description="the device ID of the device to which this item pertains")
|
||||
private long deviceId;
|
||||
|
||||
@JsonProperty
|
||||
@Schema(description="the registration ID for the device")
|
||||
private int registrationId;
|
||||
|
||||
@JsonProperty
|
||||
@Schema(description="the signed elliptic-curve prekey for the device, if one has been set")
|
||||
private SignedPreKey signedPreKey;
|
||||
|
||||
@JsonProperty
|
||||
@Schema(description="an unsigned elliptic-curve prekey for the device, if any remain")
|
||||
private PreKey preKey;
|
||||
|
||||
@JsonProperty
|
||||
@Schema(description="a signed post-quantum prekey for the device " +
|
||||
"(a one-time prekey if any remain, otherwise the last-resort prekey if one has been set)")
|
||||
private SignedPreKey pqPreKey;
|
||||
|
||||
public PreKeyResponseItem() {}
|
||||
|
||||
public PreKeyResponseItem(long deviceId, int registrationId, SignedPreKey signedPreKey, PreKey preKey) {
|
||||
this.deviceId = deviceId;
|
||||
public PreKeyResponseItem(long deviceId, int registrationId, SignedPreKey signedPreKey, PreKey preKey, SignedPreKey pqPreKey) {
|
||||
this.deviceId = deviceId;
|
||||
this.registrationId = registrationId;
|
||||
this.signedPreKey = signedPreKey;
|
||||
this.preKey = preKey;
|
||||
this.signedPreKey = signedPreKey;
|
||||
this.preKey = preKey;
|
||||
this.pqPreKey = pqPreKey;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -40,6 +51,11 @@ public class PreKeyResponseItem {
|
||||
return preKey;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public SignedPreKey getPqPreKey() {
|
||||
return pqPreKey;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public int getRegistrationId() {
|
||||
return registrationId;
|
||||
|
||||
@@ -5,24 +5,38 @@
|
||||
package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import static com.codahale.metrics.MetricRegistry.name;
|
||||
|
||||
import io.micrometer.core.instrument.Counter;
|
||||
import io.micrometer.core.instrument.Metrics;
|
||||
import java.util.Base64;
|
||||
import java.util.Collection;
|
||||
import org.signal.libsignal.protocol.InvalidKeyException;
|
||||
import org.signal.libsignal.protocol.ecc.Curve;
|
||||
import org.signal.libsignal.protocol.ecc.ECPublicKey;
|
||||
|
||||
public abstract class PreKeySignatureValidator {
|
||||
public static final boolean validatePreKeySignature(final String identityKeyB64, final SignedPreKey spk) {
|
||||
public static final Counter INVALID_SIGNATURE_COUNTER =
|
||||
Metrics.counter(name(PreKeySignatureValidator.class, "invalidPreKeySignature"));
|
||||
|
||||
public static final boolean validatePreKeySignatures(final String identityKeyB64, final Collection<SignedPreKey> spks) {
|
||||
try {
|
||||
final byte[] identityKeyBytes = Base64.getDecoder().decode(identityKeyB64);
|
||||
final byte[] prekeyBytes = Base64.getDecoder().decode(spk.getPublicKey());
|
||||
final byte[] prekeySignatureBytes = Base64.getDecoder().decode(spk.getSignature());
|
||||
|
||||
final ECPublicKey identityKey = Curve.decodePoint(identityKeyBytes, 0);
|
||||
|
||||
return identityKey.verifySignature(prekeyBytes, prekeySignatureBytes);
|
||||
final boolean success = spks.stream().allMatch(spk -> {
|
||||
final byte[] prekeyBytes = Base64.getDecoder().decode(spk.getPublicKey());
|
||||
final byte[] prekeySignatureBytes = Base64.getDecoder().decode(spk.getSignature());
|
||||
|
||||
return identityKey.verifySignature(prekeyBytes, prekeySignatureBytes);
|
||||
});
|
||||
|
||||
if (!success) {
|
||||
INVALID_SIGNATURE_COUNTER.increment();
|
||||
}
|
||||
|
||||
return success;
|
||||
} catch (IllegalArgumentException | InvalidKeyException e) {
|
||||
Metrics.counter(name(PreKeySignatureValidator.class, "invalidPreKeySignature")).increment();
|
||||
INVALID_SIGNATURE_COUNTER.increment();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ package org.whispersystems.textsecuregcm.entities;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.AssertTrue;
|
||||
@@ -15,26 +17,59 @@ import javax.validation.constraints.NotNull;
|
||||
public class PreKeyState {
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
@Valid
|
||||
@Schema(description="A list of unsigned elliptic-curve prekeys to use for this device. " +
|
||||
"If present and not empty, replaces all stored unsigned EC prekeys for the device; " +
|
||||
"if absent or empty, any stored unsigned EC prekeys for the device are not deleted.")
|
||||
private List<PreKey> preKeys;
|
||||
|
||||
@JsonProperty
|
||||
@NotNull
|
||||
@Valid
|
||||
@Schema(description="An optional signed elliptic-curve prekey to use for this device. " +
|
||||
"If present, replaces the stored signed elliptic-curve prekey for the device; " +
|
||||
"if absent, the stored signed prekey is not deleted. " +
|
||||
"If present, must have a valid signature from the identity key in this request.")
|
||||
private SignedPreKey signedPreKey;
|
||||
|
||||
@JsonProperty
|
||||
@Valid
|
||||
@Schema(description="A list of signed post-quantum one-time prekeys to use for this device. " +
|
||||
"Each key must have a valid signature from the identity key in this request. " +
|
||||
"If present and not empty, replaces all stored unsigned PQ prekeys for the device; " +
|
||||
"if absent or empty, any stored unsigned PQ prekeys for the device are not deleted.")
|
||||
private List<SignedPreKey> pqPreKeys;
|
||||
|
||||
@JsonProperty
|
||||
@Valid
|
||||
@Schema(description="An optional signed last-resort post-quantum prekey to use for this device. " +
|
||||
"If present, replaces the stored signed post-quantum last-resort prekey for the device; " +
|
||||
"if absent, a stored last-resort prekey will *not* be deleted. " +
|
||||
"If present, must have a valid signature from the identity key in this request.")
|
||||
private SignedPreKey pqLastResortPreKey;
|
||||
|
||||
@JsonProperty
|
||||
@NotEmpty
|
||||
@NotNull
|
||||
@Schema(description="Required. " +
|
||||
"The public identity key for this identity (account or phone-number identity). " +
|
||||
"If this device is not the primary device for the account, " +
|
||||
"must match the existing stored identity key for this identity.")
|
||||
private String identityKey;
|
||||
|
||||
public PreKeyState() {}
|
||||
|
||||
@VisibleForTesting
|
||||
public PreKeyState(String identityKey, SignedPreKey signedPreKey, List<PreKey> keys) {
|
||||
this.identityKey = identityKey;
|
||||
this.signedPreKey = signedPreKey;
|
||||
this.preKeys = keys;
|
||||
this(identityKey, signedPreKey, keys, null, null);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public PreKeyState(String identityKey, SignedPreKey signedPreKey, List<PreKey> keys, List<SignedPreKey> pqKeys, SignedPreKey pqLastResortKey) {
|
||||
this.identityKey = identityKey;
|
||||
this.signedPreKey = signedPreKey;
|
||||
this.preKeys = keys;
|
||||
this.pqPreKeys = pqKeys;
|
||||
this.pqLastResortPreKey = pqLastResortKey;
|
||||
}
|
||||
|
||||
public List<PreKey> getPreKeys() {
|
||||
@@ -45,12 +80,30 @@ public class PreKeyState {
|
||||
return signedPreKey;
|
||||
}
|
||||
|
||||
public List<SignedPreKey> getPqPreKeys() {
|
||||
return pqPreKeys;
|
||||
}
|
||||
|
||||
public SignedPreKey getPqLastResortPreKey() {
|
||||
return pqLastResortPreKey;
|
||||
}
|
||||
|
||||
public String getIdentityKey() {
|
||||
return identityKey;
|
||||
}
|
||||
|
||||
@AssertTrue
|
||||
public boolean isSignatureValid() {
|
||||
return PreKeySignatureValidator.validatePreKeySignature(identityKey, signedPreKey);
|
||||
public boolean isSignatureValidOnEachSignedKey() {
|
||||
List<SignedPreKey> spks = new ArrayList<>();
|
||||
if (pqPreKeys != null) {
|
||||
spks.addAll(pqPreKeys);
|
||||
}
|
||||
if (pqLastResortPreKey != null) {
|
||||
spks.add(pqLastResortPreKey);
|
||||
}
|
||||
if (signedPreKey != null) {
|
||||
spks.add(signedPreKey);
|
||||
}
|
||||
return spks.isEmpty() || PreKeySignatureValidator.validatePreKeySignatures(identityKey, spks);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,5 +45,4 @@ public class SignedPreKey extends PreKey {
|
||||
return super.hashCode() ^ signature.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user