From 919cc7e5ebd78e515b8155af2ea58556cad46d2a Mon Sep 17 00:00:00 2001
From: Jon Chambers <63609320+jon-signal@users.noreply.github.com>
Date: Thu, 4 May 2023 17:10:51 -0400
Subject: [PATCH] Update libsignal to 0.23
---
pom.xml | 2 +-
.../UnidentifiedDeliveryConfiguration.java | 3 +-
.../controllers/ProfileController.java | 124 +--------
.../PniCredentialProfileResponse.java | 36 ---
.../PniCredentialResponseAdapter.java | 41 ---
.../ProfileKeyCredentialProfileResponse.java | 36 ---
.../ProfileKeyCredentialResponseAdapter.java | 41 ---
.../workers/CertificateCommand.java | 3 +-
.../auth/CertificateGeneratorTest.java | 2 +-
.../controllers/ProfileControllerTest.java | 242 ++----------------
.../CertificateControllerTest.java | 3 +-
11 files changed, 41 insertions(+), 492 deletions(-)
delete mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/entities/PniCredentialProfileResponse.java
delete mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/entities/PniCredentialResponseAdapter.java
delete mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/entities/ProfileKeyCredentialProfileResponse.java
delete mode 100644 service/src/main/java/org/whispersystems/textsecuregcm/entities/ProfileKeyCredentialResponseAdapter.java
diff --git a/pom.xml b/pom.xml
index ae29bb099..c4c70a9b8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -290,7 +290,7 @@
org.signal
libsignal-server
- 0.22.0
+ 0.23.0
org.apache.logging.log4j
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/UnidentifiedDeliveryConfiguration.java b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/UnidentifiedDeliveryConfiguration.java
index 123d34447..9b8968972 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/configuration/UnidentifiedDeliveryConfiguration.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/configuration/UnidentifiedDeliveryConfiguration.java
@@ -8,6 +8,7 @@ package org.whispersystems.textsecuregcm.configuration;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.ecc.Curve;
import org.signal.libsignal.protocol.ecc.ECPrivateKey;
import org.whispersystems.textsecuregcm.util.ByteArrayAdapter;
@@ -37,7 +38,7 @@ public class UnidentifiedDeliveryConfiguration {
return certificate;
}
- public ECPrivateKey getPrivateKey() {
+ public ECPrivateKey getPrivateKey() throws InvalidKeyException {
return Curve.decodePrivatePoint(privateKey);
}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java
index 99ea4ff62..42b9b3422 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ProfileController.java
@@ -46,8 +46,6 @@ import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.ws.rs.BadRequestException;
import javax.ws.rs.Consumes;
-import javax.ws.rs.DefaultValue;
-import javax.ws.rs.ForbiddenException;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.NotAuthorizedException;
@@ -69,10 +67,8 @@ import org.apache.commons.lang3.StringUtils;
import org.signal.libsignal.zkgroup.InvalidInputException;
import org.signal.libsignal.zkgroup.VerificationFailedException;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredentialResponse;
-import org.signal.libsignal.zkgroup.profiles.PniCredentialResponse;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCommitment;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialRequest;
-import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialResponse;
import org.signal.libsignal.zkgroup.profiles.ServerZkProfileOperations;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -90,9 +86,7 @@ import org.whispersystems.textsecuregcm.entities.BatchIdentityCheckResponse;
import org.whispersystems.textsecuregcm.entities.CreateProfileRequest;
import org.whispersystems.textsecuregcm.entities.CredentialProfileResponse;
import org.whispersystems.textsecuregcm.entities.ExpiringProfileKeyCredentialProfileResponse;
-import org.whispersystems.textsecuregcm.entities.PniCredentialProfileResponse;
import org.whispersystems.textsecuregcm.entities.ProfileAvatarUploadAttributes;
-import org.whispersystems.textsecuregcm.entities.ProfileKeyCredentialProfileResponse;
import org.whispersystems.textsecuregcm.entities.UserCapabilities;
import org.whispersystems.textsecuregcm.entities.VersionedProfileResponse;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
@@ -137,14 +131,10 @@ public class ProfileController {
@VisibleForTesting
static final Duration EXPIRING_PROFILE_KEY_CREDENTIAL_EXPIRATION = Duration.ofDays(7);
- private static final String PROFILE_KEY_CREDENTIAL_TYPE = "profileKey";
- private static final String PNI_CREDENTIAL_TYPE = "pni";
private static final String EXPIRING_PROFILE_KEY_CREDENTIAL_TYPE = "expiringProfileKey";
private static final Counter VERSION_NOT_FOUND_COUNTER = Metrics.counter(name(ProfileController.class, "versionNotFound"));
private static final String INVALID_ACCEPT_LANGUAGE_COUNTER_NAME = name(ProfileController.class, "invalidAcceptLanguage");
- private static final String GET_PROFILE_CREDENTIAL_COUNTER_NAME = name(ProfileController.class, "getProfileCredential");
- private static final String CREDENTIAL_TYPE_TAG_NAME = "credentialType";
public ProfileController(
Clock clock,
@@ -272,56 +262,23 @@ public class ProfileController {
@PathParam("uuid") UUID uuid,
@PathParam("version") String version,
@PathParam("credentialRequest") String credentialRequest,
- @QueryParam("credentialType") @DefaultValue(PROFILE_KEY_CREDENTIAL_TYPE) String credentialType)
+ @QueryParam("credentialType") String credentialType)
throws RateLimitExceededException {
+ if (!EXPIRING_PROFILE_KEY_CREDENTIAL_TYPE.equals(credentialType)) {
+ throw new BadRequestException();
+ }
+
final Optional maybeRequester = auth.map(AuthenticatedAccount::getAccount);
final Account targetAccount = verifyPermissionToReceiveAccountIdentityProfile(maybeRequester, accessKey, uuid);
final boolean isSelf = isSelfProfileRequest(maybeRequester, uuid);
- String credentialTypeTagValue = "unrecognized";
-
- try {
- switch (credentialType) {
- case PROFILE_KEY_CREDENTIAL_TYPE -> {
- credentialTypeTagValue = PROFILE_KEY_CREDENTIAL_TYPE;
-
- return buildProfileKeyCredentialProfileResponse(targetAccount,
- version,
- credentialRequest,
- isSelf,
- containerRequestContext);
- }
-
- case PNI_CREDENTIAL_TYPE -> {
- credentialTypeTagValue = PNI_CREDENTIAL_TYPE;
-
- if (!isSelf) {
- throw new ForbiddenException();
- }
-
- return buildPniCredentialProfileResponse(targetAccount,
- version,
- credentialRequest,
- containerRequestContext);
- }
-
- case EXPIRING_PROFILE_KEY_CREDENTIAL_TYPE -> {
- credentialTypeTagValue = EXPIRING_PROFILE_KEY_CREDENTIAL_TYPE;
-
- return buildExpiringProfileKeyCredentialProfileResponse(targetAccount,
- version,
- credentialRequest,
- isSelf,
- Instant.now().plus(EXPIRING_PROFILE_KEY_CREDENTIAL_EXPIRATION).truncatedTo(ChronoUnit.DAYS),
- containerRequestContext);
- }
-
- default -> throw new BadRequestException();
- }
- } finally {
- Metrics.counter(GET_PROFILE_CREDENTIAL_COUNTER_NAME, CREDENTIAL_TYPE_TAG_NAME, credentialTypeTagValue).increment();
- }
+ return buildExpiringProfileKeyCredentialProfileResponse(targetAccount,
+ version,
+ credentialRequest,
+ isSelf,
+ Instant.now().plus(EXPIRING_PROFILE_KEY_CREDENTIAL_EXPIRATION).truncatedTo(ChronoUnit.DAYS),
+ containerRequestContext);
}
// Although clients should generally be using versioned profiles wherever possible, there are still a few lingering
@@ -443,35 +400,6 @@ public class ProfileController {
});
}
- private ProfileKeyCredentialProfileResponse buildProfileKeyCredentialProfileResponse(final Account account,
- final String version,
- final String encodedCredentialRequest,
- final boolean isSelf,
- final ContainerRequestContext containerRequestContext) {
-
- final ProfileKeyCredentialResponse profileKeyCredentialResponse = profilesManager.get(account.getUuid(), version)
- .map(profile -> getProfileCredential(encodedCredentialRequest, profile, account.getUuid()))
- .orElse(null);
-
- return new ProfileKeyCredentialProfileResponse(
- buildVersionedProfileResponse(account, version, isSelf, containerRequestContext),
- profileKeyCredentialResponse);
- }
-
- private PniCredentialProfileResponse buildPniCredentialProfileResponse(final Account account,
- final String version,
- final String encodedCredentialRequest,
- final ContainerRequestContext containerRequestContext) {
-
- final PniCredentialResponse pniCredentialResponse = profilesManager.get(account.getUuid(), version)
- .map(profile -> getPniCredential(encodedCredentialRequest, profile, account.getUuid(), account.getPhoneNumberIdentifier()))
- .orElse(null);
-
- return new PniCredentialProfileResponse(
- buildVersionedProfileResponse(account, version, true, containerRequestContext),
- pniCredentialResponse);
- }
-
private ExpiringProfileKeyCredentialProfileResponse buildExpiringProfileKeyCredentialProfileResponse(
final Account account,
final String version,
@@ -542,36 +470,6 @@ public class ProfileController {
account.getPhoneNumberIdentifier());
}
- private ProfileKeyCredentialResponse getProfileCredential(final String encodedProfileCredentialRequest,
- final VersionedProfile profile,
- final UUID uuid) {
- try {
- final ProfileKeyCommitment commitment = new ProfileKeyCommitment(profile.getCommitment());
- final ProfileKeyCredentialRequest request = new ProfileKeyCredentialRequest(
- HexFormat.of().parseHex(encodedProfileCredentialRequest));
-
- return zkProfileOperations.issueProfileKeyCredential(request, uuid, commitment);
- } catch (IllegalArgumentException | VerificationFailedException | InvalidInputException e) {
- throw new WebApplicationException(e, Response.status(Response.Status.BAD_REQUEST).build());
- }
- }
-
- private PniCredentialResponse getPniCredential(final String encodedCredentialRequest,
- final VersionedProfile profile,
- final UUID accountIdentifier,
- final UUID phoneNumberIdentifier) {
-
- try {
- final ProfileKeyCommitment commitment = new ProfileKeyCommitment(profile.getCommitment());
- final ProfileKeyCredentialRequest request = new ProfileKeyCredentialRequest(
- HexFormat.of().parseHex(encodedCredentialRequest));
-
- return zkProfileOperations.issuePniCredential(request, accountIdentifier, phoneNumberIdentifier, commitment);
- } catch (IllegalArgumentException | VerificationFailedException | InvalidInputException e) {
- throw new WebApplicationException(e, Response.status(Response.Status.BAD_REQUEST).build());
- }
- }
-
private ExpiringProfileKeyCredentialResponse getExpiringProfileKeyCredentialResponse(
final String encodedCredentialRequest,
final VersionedProfile profile,
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/PniCredentialProfileResponse.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/PniCredentialProfileResponse.java
deleted file mode 100644
index 327bf0888..000000000
--- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/PniCredentialProfileResponse.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2013-2021 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.entities;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import javax.annotation.Nullable;
-import org.signal.libsignal.zkgroup.profiles.PniCredentialResponse;
-
-public class PniCredentialProfileResponse extends CredentialProfileResponse {
-
- @JsonProperty
- @JsonSerialize(using = PniCredentialResponseAdapter.Serializing.class)
- @JsonDeserialize(using = PniCredentialResponseAdapter.Deserializing.class)
- @Nullable
- private PniCredentialResponse pniCredential;
-
- public PniCredentialProfileResponse() {
- }
-
- public PniCredentialProfileResponse(final VersionedProfileResponse versionedProfileResponse,
- @Nullable final PniCredentialResponse pniCredential) {
-
- super(versionedProfileResponse);
- this.pniCredential = pniCredential;
- }
-
- @Nullable
- public PniCredentialResponse getPniCredential() {
- return pniCredential;
- }
-}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/PniCredentialResponseAdapter.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/PniCredentialResponseAdapter.java
deleted file mode 100644
index a981bd0d1..000000000
--- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/PniCredentialResponseAdapter.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013-2020 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.entities;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import java.io.IOException;
-import java.util.Base64;
-import org.signal.libsignal.zkgroup.InvalidInputException;
-import org.signal.libsignal.zkgroup.profiles.PniCredentialResponse;
-
-public class PniCredentialResponseAdapter {
-
- public static class Serializing extends JsonSerializer {
- @Override
- public void serialize(PniCredentialResponse response, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
- throws IOException {
- if (response == null) jsonGenerator.writeNull();
- else jsonGenerator.writeString(Base64.getEncoder().encodeToString(response.serialize()));
- }
- }
-
- public static class Deserializing extends JsonDeserializer {
- @Override
- public PniCredentialResponse deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
- throws IOException {
- try {
- return new PniCredentialResponse(Base64.getDecoder().decode(jsonParser.getValueAsString()));
- } catch (InvalidInputException e) {
- throw new IOException(e);
- }
- }
- }
-}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/ProfileKeyCredentialProfileResponse.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/ProfileKeyCredentialProfileResponse.java
deleted file mode 100644
index 72f00fd78..000000000
--- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/ProfileKeyCredentialProfileResponse.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2013-2021 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.entities;
-
-import com.fasterxml.jackson.annotation.JsonProperty;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialResponse;
-import javax.annotation.Nullable;
-
-public class ProfileKeyCredentialProfileResponse extends CredentialProfileResponse {
-
- @JsonProperty
- @JsonSerialize(using = ProfileKeyCredentialResponseAdapter.Serializing.class)
- @JsonDeserialize(using = ProfileKeyCredentialResponseAdapter.Deserializing.class)
- @Nullable
- private ProfileKeyCredentialResponse credential;
-
- public ProfileKeyCredentialProfileResponse() {
- }
-
- public ProfileKeyCredentialProfileResponse(final VersionedProfileResponse versionedProfileResponse,
- @Nullable final ProfileKeyCredentialResponse credential) {
-
- super(versionedProfileResponse);
- this.credential = credential;
- }
-
- @Nullable
- public ProfileKeyCredentialResponse getCredential() {
- return credential;
- }
-}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/entities/ProfileKeyCredentialResponseAdapter.java b/service/src/main/java/org/whispersystems/textsecuregcm/entities/ProfileKeyCredentialResponseAdapter.java
deleted file mode 100644
index ff60178d7..000000000
--- a/service/src/main/java/org/whispersystems/textsecuregcm/entities/ProfileKeyCredentialResponseAdapter.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013-2020 Signal Messenger, LLC
- * SPDX-License-Identifier: AGPL-3.0-only
- */
-
-package org.whispersystems.textsecuregcm.entities;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonDeserializer;
-import com.fasterxml.jackson.databind.JsonSerializer;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import java.io.IOException;
-import java.util.Base64;
-import org.signal.libsignal.zkgroup.InvalidInputException;
-import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialResponse;
-
-public class ProfileKeyCredentialResponseAdapter {
-
- public static class Serializing extends JsonSerializer {
- @Override
- public void serialize(ProfileKeyCredentialResponse response, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
- throws IOException {
- if (response == null) jsonGenerator.writeNull();
- else jsonGenerator.writeString(Base64.getEncoder().encodeToString(response.serialize()));
- }
- }
-
- public static class Deserializing extends JsonDeserializer {
- @Override
- public ProfileKeyCredentialResponse deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
- throws IOException {
- try {
- return new ProfileKeyCredentialResponse(Base64.getDecoder().decode(jsonParser.getValueAsString()));
- } catch (InvalidInputException e) {
- throw new IOException(e);
- }
- }
- }
-}
diff --git a/service/src/main/java/org/whispersystems/textsecuregcm/workers/CertificateCommand.java b/service/src/main/java/org/whispersystems/textsecuregcm/workers/CertificateCommand.java
index c0186c25a..b54aaae0a 100644
--- a/service/src/main/java/org/whispersystems/textsecuregcm/workers/CertificateCommand.java
+++ b/service/src/main/java/org/whispersystems/textsecuregcm/workers/CertificateCommand.java
@@ -15,7 +15,6 @@ import org.signal.libsignal.protocol.ecc.ECKeyPair;
import org.signal.libsignal.protocol.ecc.ECPrivateKey;
import org.whispersystems.textsecuregcm.entities.MessageProtos;
-import java.io.IOException;
import java.security.InvalidKeyException;
import java.util.Base64;
import java.util.Set;
@@ -64,7 +63,7 @@ public class CertificateCommand extends Command {
System.out.println("Private key: " + Base64.getEncoder().encodeToString(keyPair.getPrivateKey().serialize()));
}
- private void runCertificateCommand(Namespace namespace) throws IOException, InvalidKeyException {
+ private void runCertificateCommand(Namespace namespace) throws InvalidKeyException, org.signal.libsignal.protocol.InvalidKeyException {
if (namespace.getString("key") == null) {
System.out.println("No key specified!");
return;
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/auth/CertificateGeneratorTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/auth/CertificateGeneratorTest.java
index 62903a7e9..7bb8a4c19 100644
--- a/service/src/test/java/org/whispersystems/textsecuregcm/auth/CertificateGeneratorTest.java
+++ b/service/src/test/java/org/whispersystems/textsecuregcm/auth/CertificateGeneratorTest.java
@@ -25,7 +25,7 @@ class CertificateGeneratorTest {
private static final String IDENTITY_KEY = "BcxxDU9FGMda70E7+Uvm7pnQcEdXQ64aJCpPUeRSfcFo";
@Test
- void testCreateFor() throws IOException, InvalidKeyException {
+ void testCreateFor() throws IOException, InvalidKeyException, org.signal.libsignal.protocol.InvalidKeyException {
final Account account = mock(Account.class);
final Device device = mock(Device.class);
final CertificateGenerator certificateGenerator = new CertificateGenerator(Base64.getDecoder().decode(SIGNING_CERTIFICATE), Curve.decodePrivatePoint(Base64.getDecoder().decode(SIGNING_KEY)), 1);
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ProfileControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ProfileControllerTest.java
index 14374ce1f..44ee1979a 100644
--- a/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ProfileControllerTest.java
+++ b/service/src/test/java/org/whispersystems/textsecuregcm/controllers/ProfileControllerTest.java
@@ -67,12 +67,10 @@ import org.signal.libsignal.zkgroup.ServerSecretParams;
import org.signal.libsignal.zkgroup.VerificationFailedException;
import org.signal.libsignal.zkgroup.profiles.ClientZkProfileOperations;
import org.signal.libsignal.zkgroup.profiles.ExpiringProfileKeyCredentialResponse;
-import org.signal.libsignal.zkgroup.profiles.PniCredentialResponse;
import org.signal.libsignal.zkgroup.profiles.ProfileKey;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCommitment;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialRequest;
import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialRequestContext;
-import org.signal.libsignal.zkgroup.profiles.ProfileKeyCredentialResponse;
import org.signal.libsignal.zkgroup.profiles.ServerZkProfileOperations;
import org.whispersystems.textsecuregcm.auth.AuthenticatedAccount;
import org.whispersystems.textsecuregcm.auth.DisabledPermittedAuthenticatedAccount;
@@ -88,9 +86,7 @@ import org.whispersystems.textsecuregcm.entities.BatchIdentityCheckRequest;
import org.whispersystems.textsecuregcm.entities.BatchIdentityCheckResponse;
import org.whispersystems.textsecuregcm.entities.CreateProfileRequest;
import org.whispersystems.textsecuregcm.entities.ExpiringProfileKeyCredentialProfileResponse;
-import org.whispersystems.textsecuregcm.entities.PniCredentialProfileResponse;
import org.whispersystems.textsecuregcm.entities.ProfileAvatarUploadAttributes;
-import org.whispersystems.textsecuregcm.entities.ProfileKeyCredentialProfileResponse;
import org.whispersystems.textsecuregcm.entities.VersionedProfileResponse;
import org.whispersystems.textsecuregcm.limits.RateLimiter;
import org.whispersystems.textsecuregcm.limits.RateLimiters;
@@ -868,6 +864,29 @@ class ProfileControllerTest {
assertThat(profile.getPaymentAddress()).isNull();
}
+ @Test
+ void testGetProfileWithExpiringProfileKeyCredentialVersionNotFound() throws VerificationFailedException {
+ final Account account = mock(Account.class);
+ when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
+ when(account.getCurrentProfileVersion()).thenReturn(Optional.of("version"));
+ when(account.isEnabled()).thenReturn(true);
+
+ when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID)).thenReturn(Optional.of(account));
+ when(profilesManager.get(any(), any())).thenReturn(Optional.empty());
+
+ final ExpiringProfileKeyCredentialProfileResponse profile = resources.getJerseyTest()
+ .target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, "version-that-does-not-exist", "credential-request"))
+ .queryParam("credentialType", "expiringProfileKey")
+ .request()
+ .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
+ .get(ExpiringProfileKeyCredentialProfileResponse.class);
+
+ assertThat(profile.getVersionedProfileResponse().getBaseProfileResponse().getUuid()).isEqualTo(AuthHelper.VALID_UUID);
+ assertThat(profile.getCredential()).isNull();
+
+ verify(zkProfileOperations, never()).issueExpiringProfileKeyCredential(any(), any(), any(), any());
+ }
+
@Test
void testSetProfileBadges() throws InvalidInputException {
ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(AuthHelper.VALID_UUID);
@@ -963,196 +982,6 @@ class ProfileControllerTest {
new AccountBadge("TEST3", Instant.ofEpochSecond(42 + 86400), false));
}
- @ParameterizedTest
- @MethodSource
- void testGetProfileWithProfileKeyCredential(final MultivaluedMap authHeaders)
- throws VerificationFailedException, InvalidInputException {
- final String version = "version";
- final byte[] unidentifiedAccessKey = "test-uak".getBytes(StandardCharsets.UTF_8);
-
- final ServerSecretParams serverSecretParams = ServerSecretParams.generate();
- final ServerPublicParams serverPublicParams = serverSecretParams.getPublicParams();
-
- final ServerZkProfileOperations serverZkProfile = new ServerZkProfileOperations(serverSecretParams);
- final ClientZkProfileOperations clientZkProfile = new ClientZkProfileOperations(serverPublicParams);
-
- final byte[] profileKeyBytes = new byte[32];
- new SecureRandom().nextBytes(profileKeyBytes);
-
- final ProfileKey profileKey = new ProfileKey(profileKeyBytes);
- final ProfileKeyCommitment profileKeyCommitment = profileKey.getCommitment(AuthHelper.VALID_UUID);
-
- final VersionedProfile versionedProfile = mock(VersionedProfile.class);
- when(versionedProfile.getCommitment()).thenReturn(profileKeyCommitment.serialize());
-
- final ProfileKeyCredentialRequestContext profileKeyCredentialRequestContext =
- clientZkProfile.createProfileKeyCredentialRequestContext(AuthHelper.VALID_UUID, profileKey);
-
- final ProfileKeyCredentialRequest credentialRequest = profileKeyCredentialRequestContext.getRequest();
-
- final Account account = mock(Account.class);
- when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
- when(account.getCurrentProfileVersion()).thenReturn(Optional.of(version));
- when(account.isEnabled()).thenReturn(true);
- when(account.getUnidentifiedAccessKey()).thenReturn(Optional.of(unidentifiedAccessKey));
-
- final ProfileKeyCredentialResponse credentialResponse =
- serverZkProfile.issueProfileKeyCredential(credentialRequest, AuthHelper.VALID_UUID, profileKeyCommitment);
-
- when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID)).thenReturn(Optional.of(account));
- when(profilesManager.get(AuthHelper.VALID_UUID, version)).thenReturn(Optional.of(versionedProfile));
- when(zkProfileOperations.issueProfileKeyCredential(credentialRequest, AuthHelper.VALID_UUID, profileKeyCommitment))
- .thenReturn(credentialResponse);
-
- final ProfileKeyCredentialProfileResponse profile = resources.getJerseyTest()
- .target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
- HexFormat.of().formatHex(credentialRequest.serialize())))
- .request()
- .headers(authHeaders)
- .get(ProfileKeyCredentialProfileResponse.class);
-
- assertThat(profile.getVersionedProfileResponse().getBaseProfileResponse().getUuid()).isEqualTo(AuthHelper.VALID_UUID);
- assertThat(profile.getCredential()).isEqualTo(credentialResponse);
-
- verify(zkProfileOperations).issueProfileKeyCredential(credentialRequest, AuthHelper.VALID_UUID, profileKeyCommitment);
- verify(zkProfileOperations, never()).issuePniCredential(any(), any(), any(), any());
-
- final ClientZkProfileOperations clientZkProfileCipher = new ClientZkProfileOperations(serverPublicParams);
- assertThatNoException().isThrownBy(() ->
- clientZkProfileCipher.receiveProfileKeyCredential(profileKeyCredentialRequestContext, profile.getCredential()));
- }
-
- private static Stream testGetProfileWithProfileKeyCredential() {
- return Stream.of(
- Arguments.of(new MultivaluedHashMap<>(Map.of(OptionalAccess.UNIDENTIFIED, Base64.getEncoder().encodeToString(UNIDENTIFIED_ACCESS_KEY)))),
- Arguments.of(new MultivaluedHashMap<>(Map.of("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)))),
- Arguments.of(new MultivaluedHashMap<>(Map.of("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))))
- );
- }
-
- @Test
- void testGetProfileWithProfileKeyCredentialVersionNotFound() throws VerificationFailedException {
- final Account account = mock(Account.class);
- when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
- when(account.getCurrentProfileVersion()).thenReturn(Optional.of("version"));
- when(account.isEnabled()).thenReturn(true);
-
- when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID)).thenReturn(Optional.of(account));
- when(profilesManager.get(any(), any())).thenReturn(Optional.empty());
-
- final ProfileKeyCredentialProfileResponse profile = resources.getJerseyTest()
- .target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, "version-that-does-not-exist", "credential-request"))
- .request()
- .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
- .get(ProfileKeyCredentialProfileResponse.class);
-
- assertThat(profile.getVersionedProfileResponse().getBaseProfileResponse().getUuid()).isEqualTo(AuthHelper.VALID_UUID);
- assertThat(profile.getCredential()).isNull();
-
- verify(zkProfileOperations, never()).issueProfileKeyCredential(any(), any(), any());
- verify(zkProfileOperations, never()).issuePniCredential(any(), any(), any(), any());
- }
-
- @Test
- void testGetProfileWithPniCredential() throws InvalidInputException, VerificationFailedException {
- final String version = "version";
-
- final ServerSecretParams serverSecretParams = ServerSecretParams.generate();
- final ServerPublicParams serverPublicParams = serverSecretParams.getPublicParams();
- final ServerZkProfileOperations serverZkProfile = new ServerZkProfileOperations(serverSecretParams);
- final ClientZkProfileOperations clientZkProfile = new ClientZkProfileOperations(serverPublicParams);
-
- final byte[] profileKeyBytes = new byte[32];
- new SecureRandom().nextBytes(profileKeyBytes);
-
- final ProfileKey profileKey = new ProfileKey(profileKeyBytes);
- final ProfileKeyCommitment profileKeyCommitment = profileKey.getCommitment(AuthHelper.VALID_UUID);
-
- final VersionedProfile versionedProfile = mock(VersionedProfile.class);
- when(versionedProfile.getCommitment()).thenReturn(profileKeyCommitment.serialize());
-
- final ProfileKeyCredentialRequest credentialRequest =
- clientZkProfile.createPniCredentialRequestContext(AuthHelper.VALID_UUID, AuthHelper.VALID_PNI, profileKey)
- .getRequest();
-
- final Account account = mock(Account.class);
- when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
- when(account.getPhoneNumberIdentifier()).thenReturn(AuthHelper.VALID_PNI);
- when(account.getCurrentProfileVersion()).thenReturn(Optional.of(version));
- when(account.isEnabled()).thenReturn(true);
-
- final PniCredentialResponse credentialResponse =
- serverZkProfile.issuePniCredential(credentialRequest, AuthHelper.VALID_UUID, AuthHelper.VALID_PNI, profileKeyCommitment);
-
- when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID)).thenReturn(Optional.of(account));
- when(profilesManager.get(AuthHelper.VALID_UUID, version)).thenReturn(Optional.of(versionedProfile));
- when(zkProfileOperations.issuePniCredential(credentialRequest, AuthHelper.VALID_UUID, AuthHelper.VALID_PNI, profileKeyCommitment))
- .thenReturn(credentialResponse);
-
- final PniCredentialProfileResponse profile = resources.getJerseyTest()
- .target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
- HexFormat.of().formatHex(credentialRequest.serialize())))
- .queryParam("credentialType", "pni")
- .request()
- .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
- .get(PniCredentialProfileResponse.class);
-
- assertThat(profile.getVersionedProfileResponse().getBaseProfileResponse().getUuid()).isEqualTo(AuthHelper.VALID_UUID);
- assertThat(profile.getPniCredential()).isEqualTo(credentialResponse);
-
- verify(zkProfileOperations, never()).issueProfileKeyCredential(any(), any(), any());
- verify(zkProfileOperations).issuePniCredential(credentialRequest, AuthHelper.VALID_UUID, AuthHelper.VALID_PNI, profileKeyCommitment);
- }
-
- @Test
- void testGetProfileWithPniCredentialNotSelf() throws InvalidInputException, VerificationFailedException {
- final String version = "version";
-
- final ServerSecretParams serverSecretParams = ServerSecretParams.generate();
- final ServerPublicParams serverPublicParams = serverSecretParams.getPublicParams();
- final ServerZkProfileOperations serverZkProfile = new ServerZkProfileOperations(serverSecretParams);
- final ClientZkProfileOperations clientZkProfile = new ClientZkProfileOperations(serverPublicParams);
-
- final byte[] profileKeyBytes = new byte[32];
- new SecureRandom().nextBytes(profileKeyBytes);
-
- final ProfileKey profileKey = new ProfileKey(profileKeyBytes);
- final ProfileKeyCommitment profileKeyCommitment = profileKey.getCommitment(AuthHelper.VALID_UUID);
-
- final VersionedProfile versionedProfile = mock(VersionedProfile.class);
- when(versionedProfile.getCommitment()).thenReturn(profileKeyCommitment.serialize());
-
- final ProfileKeyCredentialRequest credentialRequest =
- clientZkProfile.createProfileKeyCredentialRequestContext(AuthHelper.VALID_UUID, profileKey).getRequest();
-
- final Account account = mock(Account.class);
- when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
- when(account.getPhoneNumberIdentifier()).thenReturn(AuthHelper.VALID_PNI);
- when(account.getCurrentProfileVersion()).thenReturn(Optional.of(version));
- when(account.isEnabled()).thenReturn(true);
-
- final PniCredentialResponse credentialResponse =
- serverZkProfile.issuePniCredential(credentialRequest, AuthHelper.VALID_UUID, AuthHelper.VALID_PNI, profileKeyCommitment);
-
- when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID)).thenReturn(Optional.of(account));
- when(profilesManager.get(AuthHelper.VALID_UUID, version)).thenReturn(Optional.of(versionedProfile));
- when(zkProfileOperations.issuePniCredential(credentialRequest, AuthHelper.VALID_UUID, AuthHelper.VALID_PNI, profileKeyCommitment))
- .thenReturn(credentialResponse);
-
- final Response response = resources.getJerseyTest()
- .target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, version,
- HexFormat.of().formatHex(credentialRequest.serialize())))
- .queryParam("credentialType", "pni")
- .request()
- .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID_TWO, AuthHelper.VALID_PASSWORD_TWO))
- .get();
-
- assertThat(response.getStatus()).isEqualTo(403);
-
- verify(zkProfileOperations, never()).issueProfileKeyCredential(any(), any(), any());
- verify(zkProfileOperations, never()).issuePniCredential(any(), any(), any(), any());
- }
-
@ParameterizedTest
@MethodSource
void testGetProfileWithExpiringProfileKeyCredential(final MultivaluedMap authHeaders)
@@ -1209,7 +1038,6 @@ class ProfileControllerTest {
assertThat(profile.getCredential()).isEqualTo(credentialResponse);
verify(zkProfileOperations).issueExpiringProfileKeyCredential(credentialRequest, AuthHelper.VALID_UUID, profileKeyCommitment, expiration);
- verify(zkProfileOperations, never()).issuePniCredential(any(), any(), any(), any());
final ClientZkProfileOperations clientZkProfileCipher = new ClientZkProfileOperations(serverPublicParams);
assertThatNoException().isThrownBy(() ->
@@ -1224,30 +1052,6 @@ class ProfileControllerTest {
);
}
- @Test
- void testGetProfileWithPniCredentialVersionNotFound() throws VerificationFailedException {
- final Account account = mock(Account.class);
- when(account.getUuid()).thenReturn(AuthHelper.VALID_UUID);
- when(account.getCurrentProfileVersion()).thenReturn(Optional.of("version"));
- when(account.isEnabled()).thenReturn(true);
-
- when(accountsManager.getByAccountIdentifier(AuthHelper.VALID_UUID)).thenReturn(Optional.of(account));
- when(profilesManager.get(any(), any())).thenReturn(Optional.empty());
-
- final PniCredentialProfileResponse profile = resources.getJerseyTest()
- .target(String.format("/v1/profile/%s/%s/%s", AuthHelper.VALID_UUID, "version-that-does-not-exist", "credential-request"))
- .queryParam("credentialType", "pni")
- .request()
- .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
- .get(PniCredentialProfileResponse.class);
-
- assertThat(profile.getVersionedProfileResponse().getBaseProfileResponse().getUuid()).isEqualTo(AuthHelper.VALID_UUID);
- assertThat(profile.getPniCredential()).isNull();
-
- verify(zkProfileOperations, never()).issueProfileKeyCredential(any(), any(), any());
- verify(zkProfileOperations, never()).issuePniCredential(any(), any(), any(), any());
- }
-
@Test
void testSetProfileBadgesMissingFromRequest() throws InvalidInputException {
ProfileKeyCommitment commitment = new ProfileKey(new byte[32]).getCommitment(AuthHelper.VALID_UUID);
diff --git a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/CertificateControllerTest.java b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/CertificateControllerTest.java
index fc8119a8f..d27cd71b8 100644
--- a/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/CertificateControllerTest.java
+++ b/service/src/test/java/org/whispersystems/textsecuregcm/tests/controllers/CertificateControllerTest.java
@@ -30,6 +30,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
+import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.ecc.Curve;
import org.signal.libsignal.zkgroup.ServerSecretParams;
import org.signal.libsignal.zkgroup.auth.AuthCredentialWithPniResponse;
@@ -68,7 +69,7 @@ class CertificateControllerTest {
certificateGenerator = new CertificateGenerator(Base64.getDecoder().decode(signingCertificate),
Curve.decodePrivatePoint(Base64.getDecoder().decode(signingKey)), 1);
serverZkAuthOperations = new ServerZkAuthOperations(serverSecretParams);
- } catch (IOException e) {
+ } catch (IOException | InvalidKeyException e) {
throw new AssertionError(e);
}
}