zkgroup: Add AuthCredentialWithPni

This is a variant of AuthCredential that carries two UUIDs, intended
to be a user's ACI and PNI. Why? Because when you've been invited to a
group, you may have been invited by your ACI or by your PNI, or by
both, and it's easier for clients to treat all those states the same
by having a credential that covers both identities. The downside is
that it's larger (both the data, obviously, but also the zkgroup proof
of validity, unsurprisingly).

AnyAuthCredentialPresentation gains a 'get_pni_ciphertext' method,
which will return `None` for the existing presentations and
`Some(encrypted_pni)` for the new credential. Having a separate
credential type but a common presentation type makes it easier for the
server to handle all possible credentials uniformly.
This commit is contained in:
Jordan Rose
2022-06-21 15:11:57 -07:00
committed by GitHub
parent cc217911a9
commit 70ec1ca26f
35 changed files with 1725 additions and 168 deletions

View File

@@ -6,7 +6,6 @@
package org.signal.libsignal.zkgroup.integrationtests;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
import org.signal.libsignal.protocol.util.Hex;
import org.signal.libsignal.zkgroup.InvalidInputException;
@@ -19,6 +18,8 @@ import org.signal.libsignal.zkgroup.InvalidRedemptionTimeException;
import org.signal.libsignal.zkgroup.auth.AuthCredential;
import org.signal.libsignal.zkgroup.auth.AuthCredentialPresentation;
import org.signal.libsignal.zkgroup.auth.AuthCredentialResponse;
import org.signal.libsignal.zkgroup.auth.AuthCredentialWithPni;
import org.signal.libsignal.zkgroup.auth.AuthCredentialWithPniResponse;
import org.signal.libsignal.zkgroup.auth.ClientZkAuthOperations;
import org.signal.libsignal.zkgroup.auth.ServerZkAuthOperations;
import org.signal.libsignal.zkgroup.groups.ClientZkGroupCipher;
@@ -51,6 +52,7 @@ import java.util.UUID;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
public final class ZkGroupTest extends SecureRandomTest {
@@ -127,20 +129,28 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
byte[] temp = new byte[32]; // wrong length
new ServerSecretParams(temp);
throw new AssertionError("Failed to catch invalid ServerSecretParams deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new ServerSecretParams(makeBadArray(serverSecretParams.serialize()));
throw new AssertionError("Failed to catch invalid ServerSecretParams deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
byte[] temp = new byte[32]; // wrong length
new ServerPublicParams(temp);
throw new AssertionError("Failed to catch invalid ServerPublicParams deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new ServerPublicParams(makeBadArray(serverPublicParams.serialize()));
throw new AssertionError("Failed to catch invalid ServerPublicParams deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
}
ServerZkAuthOperations serverZkAuth = new ServerZkAuthOperations(serverSecretParams);
@@ -161,25 +171,35 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
byte[] temp = new byte[10]; // wrong length
new GroupMasterKey(temp);
throw new AssertionError("Failed to catch invalid GroupMasterKey deserialize");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
byte[] temp = new byte[10]; // wrong length
new GroupSecretParams(temp);
throw new AssertionError("Failed to catch invalid GroupSecretParams deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new GroupSecretParams(makeBadArray(groupSecretParams.serialize()));
throw new AssertionError("Failed to catch invalid GroupSecretParams deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
byte[] temp = new byte[10]; // wrong length
new GroupPublicParams(temp);
throw new AssertionError("Failed to catch invalid GroupPublicParams deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new GroupPublicParams(makeBadArray(groupPublicParams.serialize()));
throw new AssertionError("Failed to catch invalid GroupPublicParams deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
}
// SERVER
@@ -199,11 +219,15 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
byte[] temp = new byte[10];
new AuthCredentialResponse(temp);
throw new AssertionError("Failed to catch invalid AuthCredentialResponse deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new AuthCredentialResponse(makeBadArray(authCredentialResponse.serialize()));
throw new AssertionError("Failed to catch invalid AuthCredentialResponse deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
}
// CLIENT - verify test
@@ -212,7 +236,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
try {
clientZkAuthCipher.receiveAuthCredential(badUuid, redemptionTime, authCredentialResponse);
throw new AssertionError("Failed to catch invalid AuthCredential 1");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
byte[] temp = authCredentialResponse.serialize();
temp[1]++;
@@ -220,7 +246,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
try {
clientZkAuthCipher.receiveAuthCredential(uuid, redemptionTime, badResponse);
throw new AssertionError("Failed to catch invalid AuthCredential 2");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
}
// Create and decrypt user entry
@@ -235,12 +263,16 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
byte[] temp = new byte[10];
new UuidCiphertext(temp);
throw new AssertionError("Failed to catch invalid UuidCiphertext deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new UuidCiphertext(makeBadArray(uuidCiphertext.serialize()));
throw new AssertionError("Failed to catch invalid UuidCiphertext deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
}
// CLIENT - verify test
@@ -250,7 +282,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
try {
clientZkGroupCipher.decryptUuid(new UuidCiphertext(temp));
throw new AssertionError("Failed to catch invalid UuidCiphertext decrypt");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
}
// CLIENT - Create presentation
@@ -266,32 +300,38 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
try {
new AuthCredentialPresentation(temp);
throw new AssertionError("Failed to catch invalid AuthCredentialPresentation deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new AuthCredentialPresentation(makeBadArray(presentation.serialize()));
throw new AssertionError("Failed to catch invalid AuthCredentialPresentation deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
}
// SERVER - Verify presentation, using times at the edge of the acceptable window
Instant redemptionInstant = Instant.ofEpochSecond(86400L * redemptionTime);
UuidCiphertext uuidCiphertextRecv = presentation.getUuidCiphertext();
assertArrayEquals(uuidCiphertext.serialize(), uuidCiphertextRecv.serialize());
assertEquals(presentation.getRedemptionTime(), redemptionTime);
assertNull(presentation.getPniCiphertext());
assertEquals(presentation.getRedemptionTime(), redemptionInstant);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, TimeUnit.MILLISECONDS.convert(123455L, TimeUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, TimeUnit.MILLISECONDS.convert(123458L, TimeUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionInstant.minus(1, ChronoUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionInstant.plus(2, ChronoUnit.DAYS));
try {
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, TimeUnit.MILLISECONDS.convert(123455L, TimeUnit.DAYS) - 1L);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionInstant.minus(1, ChronoUnit.DAYS).minus(1, ChronoUnit.SECONDS));
throw new AssertionError("verifyAuthCredentialPresentation should fail #1!");
} catch(InvalidRedemptionTimeException e) {
} catch (InvalidRedemptionTimeException e) {
// good
}
try {
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, TimeUnit.MILLISECONDS.convert(123458L, TimeUnit.DAYS) + 1L);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionInstant.plus(2, ChronoUnit.DAYS).plus(1, ChronoUnit.SECONDS));
throw new AssertionError("verifyAuthCredentialPresentation should fail #2!");
} catch(InvalidRedemptionTimeException e) {
} catch (InvalidRedemptionTimeException e) {
// good
}
@@ -299,32 +339,38 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
byte[] temp = presentation.serialize();
temp[3]++; // We need a bad presentation that passes deserialization, this seems to work
AuthCredentialPresentation presentationTemp = new AuthCredentialPresentation(temp);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, TimeUnit.MILLISECONDS.convert(123455L, TimeUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, redemptionInstant);
throw new AssertionError("verifyAuthCredentialPresentation should fail #3!");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
temp[0] = 0; // This interprets a V2 as V1, so should fail
AuthCredentialPresentation presentationTemp = new AuthCredentialPresentation(temp);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, TimeUnit.MILLISECONDS.convert(123455L, TimeUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, redemptionInstant);
throw new AssertionError("verifyAuthCredentialPresentation should fail #4");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
temp[0] = 2; // This interprets a V2 as a non-existent version, so should fail
temp[0] = 40; // This interprets a V2 as a non-existent version, so should fail
AuthCredentialPresentation presentationTemp = new AuthCredentialPresentation(temp);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, TimeUnit.MILLISECONDS.convert(123455L, TimeUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, redemptionInstant);
throw new AssertionError("verifyAuthCredentialPresentation should fail #5");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
{
// Test that V1 presentation verifies successfully
AuthCredentialPresentation presentationTemp = new AuthCredentialPresentation(authPresentationResultV1);
assertEquals(presentationTemp.serialize()[0], 0); // Check V1
assertEquals(presentationTemp.getVersion(), AuthCredentialPresentation.Version.V1);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, TimeUnit.MILLISECONDS.convert(123455L, TimeUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, redemptionInstant);
assertArrayEquals(presentationTemp.serialize(), authPresentationResultV1);
}
@@ -338,7 +384,7 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
// redemption date to compare against test vectors, it uses the current time
UUID uuid = TEST_UUID;
int redemptionTime = (int)TimeUnit.DAYS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
int redemptionTime = (int)(Instant.now().truncatedTo(ChronoUnit.DAYS).getEpochSecond() / 86400);
// Generate keys (client's are per-group, server's are not)
// ---
@@ -375,33 +421,190 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
AuthCredentialPresentation presentation = clientZkAuthCipher.createAuthCredentialPresentation(createSecureRandom(TEST_ARRAY_32_5), groupSecretParams, authCredential);
// Verify presentation, using times at the edge of the acceptable window
Instant redemptionInstant = Instant.ofEpochSecond(86400L * redemptionTime);
UuidCiphertext uuidCiphertextRecv = presentation.getUuidCiphertext();
assertArrayEquals(uuidCiphertext.serialize(), uuidCiphertextRecv.serialize());
assertEquals(presentation.getRedemptionTime(), redemptionTime);
assertEquals(presentation.getRedemptionTime(), redemptionInstant);
// By default the library uses the current time
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, TimeUnit.MILLISECONDS.convert(redemptionTime - 1L, TimeUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, TimeUnit.MILLISECONDS.convert(redemptionTime + 2L, TimeUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionInstant.minus(1, ChronoUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionInstant.plus(2, ChronoUnit.DAYS));
try {
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, TimeUnit.MILLISECONDS.convert(redemptionTime - 1L, TimeUnit.DAYS) - 1L);
throw new AssertionError("verifyAuthCredentialPresentation (current time) should fail #1!");
} catch(InvalidRedemptionTimeException e) {
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionInstant.minus(1, ChronoUnit.DAYS).minus(1, ChronoUnit.SECONDS));
throw new AssertionError("verifyAuthCredentialPresentation should fail #1!");
} catch (InvalidRedemptionTimeException e) {
// good
}
try {
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, TimeUnit.MILLISECONDS.convert(redemptionTime + 2L, TimeUnit.DAYS) + 1L);
throw new AssertionError("verifyAuthCredentialPresentation (current time) should fail #2!");
} catch(InvalidRedemptionTimeException e) {
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionInstant.plus(2, ChronoUnit.DAYS).plus(1, ChronoUnit.SECONDS));
throw new AssertionError("verifyAuthCredentialPresentation should fail #2!");
} catch (InvalidRedemptionTimeException e) {
// good
}
}
@Test
public void testAuthWithPniIntegration() throws VerificationFailedException, InvalidInputException, InvalidRedemptionTimeException {
UUID aci = TEST_UUID;
UUID pni = TEST_UUID_1;
Instant redemptionTime = Instant.now().truncatedTo(ChronoUnit.DAYS);
// Generate keys (client's are per-group, server's are not)
// ---
// SERVER
ServerSecretParams serverSecretParams = ServerSecretParams.generate(createSecureRandom(TEST_ARRAY_32));
ServerPublicParams serverPublicParams = serverSecretParams.getPublicParams();
ServerZkAuthOperations serverZkAuth = new ServerZkAuthOperations(serverSecretParams);
// CLIENT
GroupMasterKey masterKey = new GroupMasterKey(TEST_ARRAY_32_1);
GroupSecretParams groupSecretParams = GroupSecretParams.deriveFromMasterKey(masterKey);
assertArrayEquals(groupSecretParams.getMasterKey().serialize(), masterKey.serialize());
GroupPublicParams groupPublicParams = groupSecretParams.getPublicParams();
// SERVER
// Issue credential
AuthCredentialWithPniResponse authCredentialResponse = serverZkAuth.issueAuthCredentialWithPni(createSecureRandom(TEST_ARRAY_32_2), aci, pni, redemptionTime);
// CLIENT
// Receive credential
ClientZkAuthOperations clientZkAuthCipher = new ClientZkAuthOperations(serverPublicParams);
ClientZkGroupCipher clientZkGroupCipher = new ClientZkGroupCipher (groupSecretParams );
AuthCredentialWithPni authCredential = clientZkAuthCipher.receiveAuthCredentialWithPni(aci, pni, redemptionTime.getEpochSecond(), authCredentialResponse);
// CLIENT - deserialize test
{
new AuthCredentialWithPniResponse(authCredentialResponse.serialize());
try {
byte[] temp = new byte[10];
new AuthCredentialWithPniResponse(temp);
throw new AssertionError("Failed to catch invalid AuthCredentialWithPniResponse deserialize 1");
} catch (InvalidInputException e) {
// expected
}
try {
new AuthCredentialWithPniResponse(makeBadArray(authCredentialResponse.serialize()));
throw new AssertionError("Failed to catch invalid AuthCredentialWithPniResponse deserialize 2");
} catch (InvalidInputException e) {
// expected
}
}
// CLIENT - verify test
{
try {
// Switch ACI and PNI
clientZkAuthCipher.receiveAuthCredentialWithPni(pni, aci, redemptionTime.getEpochSecond(), authCredentialResponse);
throw new AssertionError("Failed to catch invalid AuthCredentialWithPni 1");
} catch (VerificationFailedException e) {
// expected
}
byte[] temp = authCredentialResponse.serialize();
temp[1]++;
AuthCredentialWithPniResponse badResponse = new AuthCredentialWithPniResponse(temp);
try {
clientZkAuthCipher.receiveAuthCredentialWithPni(aci, pni, redemptionTime.getEpochSecond(), badResponse);
throw new AssertionError("Failed to catch invalid AuthCredentialWithPni 2");
} catch (VerificationFailedException e) {
// expected
}
}
// Create and decrypt user entry
UuidCiphertext aciCiphertext = clientZkGroupCipher.encryptUuid(aci);
UUID aciPlaintext = clientZkGroupCipher.decryptUuid(aciCiphertext);
assertEquals(aci, aciPlaintext);
UuidCiphertext pniCiphertext = clientZkGroupCipher.encryptUuid(pni);
UUID pniPlaintext = clientZkGroupCipher.decryptUuid(pniCiphertext);
assertEquals(pni, pniPlaintext);
// CLIENT - Create presentation
AuthCredentialPresentation presentation = clientZkAuthCipher.createAuthCredentialPresentation(createSecureRandom(TEST_ARRAY_32_5), groupSecretParams, authCredential);
assertEquals(presentation.serialize()[0], 2); // Check V3
assertEquals(presentation.getVersion(), AuthCredentialPresentation.Version.V3);
// CLIENT - deserialize test
{
new AuthCredentialPresentation(presentation.serialize());
byte[] temp = new byte[10];
try {
new AuthCredentialPresentation(temp);
throw new AssertionError("Failed to catch invalid AuthCredentialPresentation deserialize 1");
} catch (InvalidInputException e) {
// expected
}
try {
new AuthCredentialPresentation(makeBadArray(presentation.serialize()));
throw new AssertionError("Failed to catch invalid AuthCredentialPresentation deserialize 2");
} catch (InvalidInputException e) {
// expected
}
}
// SERVER - Verify presentation, using times at the edge of the acceptable window
assertArrayEquals(aciCiphertext.serialize(), presentation.getUuidCiphertext().serialize());
assertArrayEquals(pniCiphertext.serialize(), presentation.getPniCiphertext().serialize());
assertEquals(presentation.getRedemptionTime(), redemptionTime);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionTime.minus(1, ChronoUnit.DAYS));
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionTime.plus(2, ChronoUnit.DAYS));
try {
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionTime.minus(1, ChronoUnit.DAYS).minus(1, ChronoUnit.SECONDS));
throw new AssertionError("verifyAuthCredentialPresentation should fail #1!");
} catch (InvalidRedemptionTimeException e) {
// good
}
try {
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentation, redemptionTime.plus(2, ChronoUnit.DAYS).plus(1, ChronoUnit.SECONDS));
throw new AssertionError("verifyAuthCredentialPresentation should fail #2!");
} catch (InvalidRedemptionTimeException e) {
// good
}
try {
byte[] temp = presentation.serialize();
temp[3] += 5; // We need a bad presentation that passes deserialization, this seems to work
AuthCredentialPresentation presentationTemp = new AuthCredentialPresentation(temp);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, redemptionTime);
throw new AssertionError("verifyAuthCredentialPresentation should fail #3!");
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
temp[0] = 0; // This interprets a V3 as V1, so should fail
AuthCredentialPresentation presentationTemp = new AuthCredentialPresentation(temp);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, redemptionTime);
throw new AssertionError("verifyAuthCredentialPresentation should fail #4");
} catch (InvalidInputException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
temp[0] = 40; // This interprets a V3 as a non-existent version, so should fail
AuthCredentialPresentation presentationTemp = new AuthCredentialPresentation(temp);
serverZkAuth.verifyAuthCredentialPresentation(groupPublicParams, presentationTemp, redemptionTime);
throw new AssertionError("verifyAuthCredentialPresentation should fail #5");
} catch (InvalidInputException e) {
// expected
}
}
@Test
public void testProfileKeyIntegration() throws VerificationFailedException, InvalidInputException, UnsupportedEncodingException {
@@ -438,11 +641,15 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
byte[] temp = new byte[10];
new ProfileKeyCredentialRequestContext(temp);
throw new AssertionError("Failed to catch invalid ProfileKeyCredentialResponse deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new ProfileKeyCredentialRequestContext(makeBadArray(context.serialize()));
throw new AssertionError("Failed to catch invalid ProfileKeyCredentialRequestContext deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
}
// SERVER
@@ -456,7 +663,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
try {
serverZkProfile.issueProfileKeyCredential(createSecureRandom(TEST_ARRAY_32_4), badRequest, uuid, profileKeyCommitment);
throw new AssertionError("Failed to catch invalid ProfileKeyCredentialRequest");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
}
// CLIENT
@@ -480,12 +689,16 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
byte[] temp = new byte[10];
new ProfileKeyCiphertext(temp);
throw new AssertionError("Failed to catch invalid ProfileKeyCiphertext deserialize 1");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
try {
new ProfileKeyCiphertext(makeBadArray(profileKeyCiphertext.serialize()));
throw new AssertionError("Failed to catch invalid ProfileKeyCiphertext deserialize 2");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
}
// CLIENT - verify test
@@ -495,7 +708,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
try {
clientZkGroupCipher.decryptProfileKey(new ProfileKeyCiphertext(temp), uuid);
throw new AssertionError("Failed to catch invalid ProfileKeyCiphertext decrypt");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
}
ProfileKeyCredentialPresentation presentation = clientZkProfileCipher.createProfileKeyCredentialPresentation(createSecureRandom(TEST_ARRAY_32_5), groupSecretParams, profileKeyCredential);
@@ -519,7 +734,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
ProfileKeyCredentialPresentation presentationTemp = new ProfileKeyCredentialPresentation(temp);
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyProfileKeyCredentialPresentation should fail 1");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
@@ -527,7 +744,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
ProfileKeyCredentialPresentation presentationTemp = new ProfileKeyCredentialPresentation(temp);
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyProfileKeyCredentialPresentation should fail 2");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
@@ -535,7 +754,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
ProfileKeyCredentialPresentation presentationTemp = new ProfileKeyCredentialPresentation(temp);
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyProfileKeyCredentialPresentation should fail 3");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
{
// Test that V1 presentation verifies successfully
@@ -589,7 +810,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
try {
serverZkProfile.issueExpiringProfileKeyCredential(createSecureRandom(TEST_ARRAY_32_4), badRequest, uuid, profileKeyCommitment, expiration);
throw new AssertionError("Failed to catch invalid ProfileKeyCredentialRequest");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
}
// CLIENT
@@ -621,12 +844,16 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
try {
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, presentation, expiration);
throw new AssertionError("credential expired 1");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, presentation, expiration.plusSeconds(5));
throw new AssertionError("credential expired 2");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
@@ -634,7 +861,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
ProfileKeyCredentialPresentation presentationTemp = new ProfileKeyCredentialPresentation(temp);
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyProfileKeyCredentialPresentation should fail 1");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
@@ -642,7 +871,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
ProfileKeyCredentialPresentation presentationTemp = new ProfileKeyCredentialPresentation(temp);
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyProfileKeyCredentialPresentation should fail 2");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
@@ -650,7 +881,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
ProfileKeyCredentialPresentation presentationTemp = new ProfileKeyCredentialPresentation(temp);
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyProfileKeyCredentialPresentation should fail 3");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
// Test that we can encode as a V1 presentation, even though it won't verify.
ProfileKeyCredentialPresentation v1Presentation = new ProfileKeyCredentialPresentation(presentation.getStructurallyValidV1PresentationBytes());
@@ -658,7 +891,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
assertEquals(v1Presentation.getProfileKeyCiphertext(), presentation.getProfileKeyCiphertext());
try {
serverZkProfile.verifyProfileKeyCredentialPresentation(groupPublicParams, v1Presentation);
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
}
@Test
@@ -718,7 +953,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
PniCredentialPresentation presentationTemp = new PniCredentialPresentation(temp);
serverZkProfile.verifyPniCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyPniCredentialPresentation should fail 1");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
@@ -726,7 +963,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
PniCredentialPresentation presentationTemp = new PniCredentialPresentation(temp);
serverZkProfile.verifyPniCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyPniCredentialPresentation should fail 2");
} catch (VerificationFailedException e) {}
} catch (VerificationFailedException e) {
// expected
}
try {
byte[] temp = presentation.serialize();
@@ -734,7 +973,9 @@ private static final byte[] pniPresentationResultV2 = Hex.fromStringCondensedAss
PniCredentialPresentation presentationTemp = new PniCredentialPresentation(temp);
serverZkProfile.verifyPniCredentialPresentation(groupPublicParams, presentationTemp);
throw new AssertionError("verifyPniCredentialPresentation should fail 3");
} catch (InvalidInputException e) {}
} catch (InvalidInputException e) {
// expected
}
{
// Test that V1 presentation verifies successfully