mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-20 03:52:17 +02:00
Use an enum for BackupAuthCredential's level
This commit is contained in:
parent
9db74365d9
commit
9204831745
@ -60,19 +60,20 @@ public final class BackupAuthTest extends SecureRandomTest {
|
||||
GenericServerSecretParams.generate(createSecureRandom(SERVER_SECRET_RANDOM));
|
||||
Instant timestamp = Instant.now().truncatedTo(ChronoUnit.DAYS);
|
||||
BackupAuthCredentialResponse response =
|
||||
request.issueCredential(timestamp, 1L, serverSecretParams);
|
||||
request.issueCredential(timestamp, BackupLevel.MESSAGES, serverSecretParams);
|
||||
|
||||
BackupAuthCredential credential =
|
||||
context.receiveResponse(response, serverSecretParams.getPublicParams(), 1L);
|
||||
context.receiveResponse(response, serverSecretParams.getPublicParams());
|
||||
Assert.assertArrayEquals(SERIALIZED_BACKUP_ID, credential.getBackupId());
|
||||
Assert.assertArrayEquals(
|
||||
SERIALIZED_BACKUP_ID,
|
||||
credential.present(serverSecretParams.getPublicParams()).getBackupId());
|
||||
Assert.assertEquals(BackupLevel.MESSAGES, credential.getBackupLevel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackupAuthCredentialIntegration() throws VerificationFailedException {
|
||||
final long receiptLevel = 10L;
|
||||
final BackupLevel backupLevel = BackupLevel.MESSAGES;
|
||||
|
||||
// SERVER
|
||||
// Generate keys
|
||||
@ -90,16 +91,12 @@ public final class BackupAuthTest extends SecureRandomTest {
|
||||
Instant timestamp = Instant.now().truncatedTo(ChronoUnit.DAYS);
|
||||
BackupAuthCredentialResponse response =
|
||||
request.issueCredential(
|
||||
timestamp, receiptLevel, serverSecretParams, createSecureRandom(TEST_ARRAY_32_1));
|
||||
timestamp, backupLevel, serverSecretParams, createSecureRandom(TEST_ARRAY_32_1));
|
||||
|
||||
// CLIENT
|
||||
// Gets stored credential
|
||||
BackupAuthCredential credential =
|
||||
context.receiveResponse(response, serverPublicParams, receiptLevel);
|
||||
Assert.assertThrows(
|
||||
"Wrong receipt level",
|
||||
VerificationFailedException.class,
|
||||
() -> context.receiveResponse(response, serverPublicParams, receiptLevel + 1));
|
||||
BackupAuthCredential credential = context.receiveResponse(response, serverPublicParams);
|
||||
Assert.assertEquals(backupLevel, credential.getBackupLevel());
|
||||
|
||||
// CLIENT
|
||||
// Generates a presentation
|
||||
@ -111,7 +108,7 @@ public final class BackupAuthTest extends SecureRandomTest {
|
||||
presentation.verify(serverSecretParams);
|
||||
presentation.verify(timestamp.plus(1, ChronoUnit.DAYS), serverSecretParams);
|
||||
Assert.assertArrayEquals(credential.getBackupId(), presentation.getBackupId());
|
||||
Assert.assertEquals(receiptLevel, presentation.getReceiptLevel());
|
||||
Assert.assertEquals(backupLevel, presentation.getBackupLevel());
|
||||
|
||||
Assert.assertThrows(
|
||||
"Credential should be expired after 2 days",
|
||||
|
@ -117,21 +117,22 @@ public final class Native {
|
||||
|
||||
public static native void BackupAuthCredentialPresentation_CheckValidContents(byte[] presentationBytes) throws Exception;
|
||||
public static native byte[] BackupAuthCredentialPresentation_GetBackupId(byte[] presentationBytes);
|
||||
public static native long BackupAuthCredentialPresentation_GetReceiptLevel(byte[] presentationBytes);
|
||||
public static native int BackupAuthCredentialPresentation_GetBackupLevel(byte[] presentationBytes);
|
||||
public static native void BackupAuthCredentialPresentation_Verify(byte[] presentationBytes, long now, byte[] serverParamsBytes) throws Exception;
|
||||
|
||||
public static native void BackupAuthCredentialRequestContext_CheckValidContents(byte[] contextBytes) throws Exception;
|
||||
public static native byte[] BackupAuthCredentialRequestContext_GetRequest(byte[] contextBytes);
|
||||
public static native byte[] BackupAuthCredentialRequestContext_New(byte[] backupKey, UUID uuid);
|
||||
public static native byte[] BackupAuthCredentialRequestContext_ReceiveResponse(byte[] contextBytes, byte[] responseBytes, byte[] paramsBytes, long expectedReceiptLevel) throws Exception;
|
||||
public static native byte[] BackupAuthCredentialRequestContext_ReceiveResponse(byte[] contextBytes, byte[] responseBytes, byte[] paramsBytes) throws Exception;
|
||||
|
||||
public static native void BackupAuthCredentialRequest_CheckValidContents(byte[] requestBytes) throws Exception;
|
||||
public static native byte[] BackupAuthCredentialRequest_IssueDeterministic(byte[] requestBytes, long redemptionTime, long receiptLevel, byte[] paramsBytes, byte[] randomness);
|
||||
public static native byte[] BackupAuthCredentialRequest_IssueDeterministic(byte[] requestBytes, long redemptionTime, int backupLevel, byte[] paramsBytes, byte[] randomness);
|
||||
|
||||
public static native void BackupAuthCredentialResponse_CheckValidContents(byte[] responseBytes) throws Exception;
|
||||
|
||||
public static native void BackupAuthCredential_CheckValidContents(byte[] paramsBytes) throws Exception;
|
||||
public static native byte[] BackupAuthCredential_GetBackupId(byte[] credentialBytes);
|
||||
public static native int BackupAuthCredential_GetBackupLevel(byte[] credentialBytes);
|
||||
public static native byte[] BackupAuthCredential_PresentDeterministic(byte[] credentialBytes, byte[] serverParamsBytes, byte[] randomness) throws Exception;
|
||||
|
||||
public static native void CallLinkAuthCredentialPresentation_CheckValidContents(byte[] presentationBytes) throws Exception;
|
||||
|
@ -48,4 +48,9 @@ public final class BackupAuthCredential extends ByteArray {
|
||||
public byte[] getBackupId() {
|
||||
return Native.BackupAuthCredential_GetBackupId(getInternalContentsForJNI());
|
||||
}
|
||||
|
||||
public BackupLevel getBackupLevel() {
|
||||
return BackupLevel.fromValue(
|
||||
Native.BackupAuthCredential_GetBackupLevel(getInternalContentsForJNI()));
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,8 @@ public final class BackupAuthCredentialPresentation extends ByteArray {
|
||||
return Native.BackupAuthCredentialPresentation_GetBackupId(getInternalContentsForJNI());
|
||||
}
|
||||
|
||||
public long getReceiptLevel() {
|
||||
return Native.BackupAuthCredentialPresentation_GetReceiptLevel(getInternalContentsForJNI());
|
||||
public BackupLevel getBackupLevel() {
|
||||
return BackupLevel.fromValue(
|
||||
Native.BackupAuthCredentialPresentation_GetBackupLevel(getInternalContentsForJNI()));
|
||||
}
|
||||
}
|
||||
|
@ -29,29 +29,29 @@ public final class BackupAuthCredentialRequest extends ByteArray {
|
||||
*
|
||||
* @param timestamp Must be a round number of days. Use {@link Instant#truncatedTo} to ensure
|
||||
* this.
|
||||
* @param receiptLevel The receiptLevel that this credential is authorized for
|
||||
* @param backupLevel The {@link BackupLevel} that this credential is authorized for
|
||||
* @param params The params that will be used by the verifying server to verify this credential.
|
||||
*/
|
||||
public BackupAuthCredentialResponse issueCredential(
|
||||
Instant timestamp, long receiptLevel, GenericServerSecretParams params) {
|
||||
return issueCredential(timestamp, receiptLevel, params, new SecureRandom());
|
||||
Instant timestamp, BackupLevel backupLevel, GenericServerSecretParams params) {
|
||||
return issueCredential(timestamp, backupLevel, params, new SecureRandom());
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues a BackupAuthCredential, using a dedicated source of randomness.
|
||||
*
|
||||
* <p>This can be used to make tests deterministic. Prefer {@link #issueCredential(Instant, long,
|
||||
* GenericServerSecretParams)} if the source of randomness doesn't matter.
|
||||
* <p>This can be used to make tests deterministic. Prefer {@link #issueCredential(Instant,
|
||||
* BackupLevel, GenericServerSecretParams)} if the source of randomness doesn't matter.
|
||||
*
|
||||
* @param timestamp Must be a round number of days. Use {@link Instant#truncatedTo} to ensure
|
||||
* this.
|
||||
* @param receiptLevel The receiptLevel that this credential is authorized for
|
||||
* @param backupLevel The {@link BackupLevel} that this credential is authorized for
|
||||
* @param params The params that will be used by the verifying server to verify this credential.
|
||||
* @param secureRandom Used to hide the server's secrets and make the issued credential unique.
|
||||
*/
|
||||
public BackupAuthCredentialResponse issueCredential(
|
||||
Instant timestamp,
|
||||
long receiptLevel,
|
||||
BackupLevel backupLevel,
|
||||
GenericServerSecretParams params,
|
||||
SecureRandom secureRandom) {
|
||||
byte[] random = new byte[RANDOM_LENGTH];
|
||||
@ -61,7 +61,7 @@ public final class BackupAuthCredentialRequest extends ByteArray {
|
||||
Native.BackupAuthCredentialRequest_IssueDeterministic(
|
||||
getInternalContentsForJNI(),
|
||||
timestamp.getEpochSecond(),
|
||||
receiptLevel,
|
||||
backupLevel.getValue(),
|
||||
params.getInternalContentsForJNI(),
|
||||
random);
|
||||
|
||||
|
@ -44,9 +44,7 @@ public final class BackupAuthCredentialRequestContext extends ByteArray {
|
||||
}
|
||||
|
||||
public BackupAuthCredential receiveResponse(
|
||||
BackupAuthCredentialResponse response,
|
||||
GenericServerPublicParams params,
|
||||
long expectedReceiptLevel)
|
||||
BackupAuthCredentialResponse response, GenericServerPublicParams params)
|
||||
throws VerificationFailedException {
|
||||
final byte[] newContents =
|
||||
filterExceptions(
|
||||
@ -55,8 +53,7 @@ public final class BackupAuthCredentialRequestContext extends ByteArray {
|
||||
Native.BackupAuthCredentialRequestContext_ReceiveResponse(
|
||||
getInternalContentsForJNI(),
|
||||
response.getInternalContentsForJNI(),
|
||||
params.getInternalContentsForJNI(),
|
||||
expectedReceiptLevel));
|
||||
params.getInternalContentsForJNI()));
|
||||
|
||||
try {
|
||||
return new BackupAuthCredential(newContents);
|
||||
|
@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright 2024 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
package org.signal.libsignal.zkgroup.backups;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public enum BackupLevel {
|
||||
// This must match the Rust version of the enum.
|
||||
MESSAGES(200),
|
||||
MEDIA(201);
|
||||
|
||||
private static final Map<Integer, BackupLevel> LOOKUP =
|
||||
Arrays.stream(BackupLevel.values())
|
||||
.collect(Collectors.toMap(BackupLevel::getValue, Function.identity()));
|
||||
|
||||
private final int value;
|
||||
|
||||
BackupLevel(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public static BackupLevel fromValue(int value) {
|
||||
BackupLevel backupLevel = LOOKUP.get(value);
|
||||
if (backupLevel == null) {
|
||||
throw new IllegalArgumentException("Invalid backup level: " + value);
|
||||
}
|
||||
return backupLevel;
|
||||
}
|
||||
}
|
5
node/Native.d.ts
vendored
5
node/Native.d.ts
vendored
@ -143,12 +143,13 @@ export function BackupAuthCredentialPresentation_Verify(presentationBytes: Buffe
|
||||
export function BackupAuthCredentialRequestContext_CheckValidContents(contextBytes: Buffer): void;
|
||||
export function BackupAuthCredentialRequestContext_GetRequest(contextBytes: Buffer): Buffer;
|
||||
export function BackupAuthCredentialRequestContext_New(backupKey: Buffer, uuid: Uuid): Buffer;
|
||||
export function BackupAuthCredentialRequestContext_ReceiveResponse(contextBytes: Buffer, responseBytes: Buffer, paramsBytes: Buffer, expectedReceiptLevel: bigint): Buffer;
|
||||
export function BackupAuthCredentialRequestContext_ReceiveResponse(contextBytes: Buffer, responseBytes: Buffer, paramsBytes: Buffer): Buffer;
|
||||
export function BackupAuthCredentialRequest_CheckValidContents(requestBytes: Buffer): void;
|
||||
export function BackupAuthCredentialRequest_IssueDeterministic(requestBytes: Buffer, redemptionTime: Timestamp, receiptLevel: bigint, paramsBytes: Buffer, randomness: Buffer): Buffer;
|
||||
export function BackupAuthCredentialRequest_IssueDeterministic(requestBytes: Buffer, redemptionTime: Timestamp, backupLevel: number, paramsBytes: Buffer, randomness: Buffer): Buffer;
|
||||
export function BackupAuthCredentialResponse_CheckValidContents(responseBytes: Buffer): void;
|
||||
export function BackupAuthCredential_CheckValidContents(paramsBytes: Buffer): void;
|
||||
export function BackupAuthCredential_GetBackupId(credentialBytes: Buffer): Buffer;
|
||||
export function BackupAuthCredential_GetBackupLevel(credentialBytes: Buffer): number;
|
||||
export function BackupAuthCredential_PresentDeterministic(credentialBytes: Buffer, serverParamsBytes: Buffer, randomness: Buffer): Buffer;
|
||||
export function CallLinkAuthCredentialPresentation_CheckValidContents(presentationBytes: Buffer): void;
|
||||
export function CallLinkAuthCredentialPresentation_GetUserId(presentationBytes: Buffer): Serialized<UuidCiphertext>;
|
||||
|
@ -57,6 +57,7 @@ import {
|
||||
ReceiptCredentialRequest,
|
||||
ReceiptCredentialRequestContext,
|
||||
ReceiptCredentialResponse,
|
||||
BackupLevel,
|
||||
} from '../zkgroup/';
|
||||
import { Aci, Pni } from '../Address';
|
||||
import { LibSignalErrorBase, Uuid } from '..';
|
||||
@ -723,7 +724,7 @@ describe('ZKGroup', () => {
|
||||
);
|
||||
|
||||
it('testDeterministic', () => {
|
||||
const receiptLevel = 1n;
|
||||
const backupLevel = BackupLevel.Messages;
|
||||
const context = BackupAuthCredentialRequestContext.create(
|
||||
BACKUP_KEY,
|
||||
TEST_USER_ID
|
||||
@ -738,19 +739,19 @@ describe('ZKGroup', () => {
|
||||
const startOfDay = now - (now % SECONDS_PER_DAY);
|
||||
const response = request.issueCredential(
|
||||
startOfDay,
|
||||
receiptLevel,
|
||||
backupLevel,
|
||||
serverSecretParams
|
||||
);
|
||||
const credential = context.receive(
|
||||
response,
|
||||
serverSecretParams.getPublicParams(),
|
||||
receiptLevel
|
||||
serverSecretParams.getPublicParams()
|
||||
);
|
||||
assert.equal(backupLevel, credential.getBackupLevel());
|
||||
assertArrayEquals(SERIALIZED_BACKUP_ID, credential.getBackupId());
|
||||
});
|
||||
|
||||
it('testIntegration', () => {
|
||||
const receiptLevel = 10n;
|
||||
const backupLevel = BackupLevel.Messages;
|
||||
|
||||
const serverSecretParams =
|
||||
GenericServerSecretParams.generateWithRandom(SERVER_SECRET_RANDOM);
|
||||
@ -768,20 +769,14 @@ describe('ZKGroup', () => {
|
||||
const startOfDay = now - (now % SECONDS_PER_DAY);
|
||||
const response = request.issueCredentialWithRandom(
|
||||
startOfDay,
|
||||
receiptLevel,
|
||||
backupLevel,
|
||||
serverSecretParams,
|
||||
TEST_ARRAY_32_1
|
||||
);
|
||||
|
||||
// client
|
||||
const credential = context.receive(
|
||||
response,
|
||||
serverPublicParams,
|
||||
receiptLevel
|
||||
);
|
||||
assert.throws(() =>
|
||||
context.receive(response, serverPublicParams, receiptLevel + 1n)
|
||||
);
|
||||
const credential = context.receive(response, serverPublicParams);
|
||||
assert.equal(backupLevel, credential.getBackupLevel());
|
||||
const presentation = credential.presentWithRandom(
|
||||
serverPublicParams,
|
||||
TEST_ARRAY_32_2
|
||||
|
@ -11,6 +11,7 @@ import { RANDOM_LENGTH } from '../internal/Constants';
|
||||
|
||||
import GenericServerPublicParams from '../GenericServerPublicParams';
|
||||
import BackupAuthCredentialPresentation from './BackupAuthCredentialPresentation';
|
||||
import BackupLevel from './BackupLevel';
|
||||
|
||||
export default class BackupAuthCredential extends ByteArray {
|
||||
private readonly __type?: never;
|
||||
@ -42,4 +43,12 @@ export default class BackupAuthCredential extends ByteArray {
|
||||
getBackupId(): Buffer {
|
||||
return Native.BackupAuthCredential_GetBackupId(this.contents);
|
||||
}
|
||||
|
||||
getBackupLevel(): BackupLevel {
|
||||
const n: number = Native.BackupAuthCredential_GetBackupLevel(this.contents);
|
||||
if (!(n in BackupLevel)) {
|
||||
throw new TypeError(`Invalid BackupLevel ${n}`);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import { RANDOM_LENGTH } from '../internal/Constants';
|
||||
|
||||
import GenericServerSecretParams from '../GenericServerSecretParams';
|
||||
import BackupAuthCredentialResponse from './BackupAuthCredentialResponse';
|
||||
import BackupLevel from './BackupLevel';
|
||||
|
||||
export default class BackupAuthCredentialRequest extends ByteArray {
|
||||
private readonly __type?: never;
|
||||
@ -21,13 +22,13 @@ export default class BackupAuthCredentialRequest extends ByteArray {
|
||||
|
||||
issueCredential(
|
||||
timestamp: number,
|
||||
receiptLevel: bigint,
|
||||
backupLevel: BackupLevel,
|
||||
params: GenericServerSecretParams
|
||||
): BackupAuthCredentialResponse {
|
||||
const random = randomBytes(RANDOM_LENGTH);
|
||||
return this.issueCredentialWithRandom(
|
||||
timestamp,
|
||||
receiptLevel,
|
||||
backupLevel,
|
||||
params,
|
||||
random
|
||||
);
|
||||
@ -35,7 +36,7 @@ export default class BackupAuthCredentialRequest extends ByteArray {
|
||||
|
||||
issueCredentialWithRandom(
|
||||
timestamp: number,
|
||||
receiptLevel: bigint,
|
||||
backupLevel: BackupLevel,
|
||||
params: GenericServerSecretParams,
|
||||
random: Buffer
|
||||
): BackupAuthCredentialResponse {
|
||||
@ -43,7 +44,7 @@ export default class BackupAuthCredentialRequest extends ByteArray {
|
||||
Native.BackupAuthCredentialRequest_IssueDeterministic(
|
||||
this.contents,
|
||||
timestamp,
|
||||
receiptLevel,
|
||||
backupLevel,
|
||||
params.contents,
|
||||
random
|
||||
)
|
||||
|
@ -44,15 +44,13 @@ export default class BackupAuthCredentialRequestContext extends ByteArray {
|
||||
|
||||
receive(
|
||||
response: BackupAuthCredentialResponse,
|
||||
params: GenericServerPublicParams,
|
||||
expectedReceiptLevel: bigint
|
||||
params: GenericServerPublicParams
|
||||
): BackupAuthCredential {
|
||||
return new BackupAuthCredential(
|
||||
Native.BackupAuthCredentialRequestContext_ReceiveResponse(
|
||||
this.contents,
|
||||
response.contents,
|
||||
params.contents,
|
||||
expectedReceiptLevel
|
||||
params.contents
|
||||
)
|
||||
);
|
||||
}
|
||||
|
11
node/ts/zkgroup/backups/BackupLevel.ts
Normal file
11
node/ts/zkgroup/backups/BackupLevel.ts
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// Copyright 2024 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
// This must match the Rust version of the enum.
|
||||
enum BackupLevel {
|
||||
Messages = 200,
|
||||
Media = 201,
|
||||
}
|
||||
export default BackupLevel;
|
@ -73,6 +73,7 @@ export { default as BackupAuthCredentialPresentation } from './backups/BackupAut
|
||||
export { default as BackupAuthCredentialRequest } from './backups/BackupAuthCredentialRequest';
|
||||
export { default as BackupAuthCredentialRequestContext } from './backups/BackupAuthCredentialRequestContext';
|
||||
export { default as BackupAuthCredentialResponse } from './backups/BackupAuthCredentialResponse';
|
||||
export { default as BackupLevel } from './backups/BackupLevel';
|
||||
|
||||
// Group Send
|
||||
|
||||
|
@ -20,7 +20,7 @@ use serde::Deserialize;
|
||||
use uuid::Uuid;
|
||||
use zkgroup::backups::{
|
||||
BackupAuthCredential, BackupAuthCredentialPresentation, BackupAuthCredentialRequest,
|
||||
BackupAuthCredentialRequestContext, BackupAuthCredentialResponse,
|
||||
BackupAuthCredentialRequestContext, BackupAuthCredentialResponse, BackupLevel,
|
||||
};
|
||||
|
||||
use crate::support::*;
|
||||
@ -995,7 +995,7 @@ fn BackupAuthCredentialRequest_CheckValidContents(
|
||||
fn BackupAuthCredentialRequest_IssueDeterministic(
|
||||
request_bytes: &[u8],
|
||||
redemption_time: Timestamp,
|
||||
receipt_level: u64,
|
||||
backup_level: AsType<BackupLevel, u8>,
|
||||
params_bytes: &[u8],
|
||||
randomness: &[u8; RANDOMNESS_LEN],
|
||||
) -> Vec<u8> {
|
||||
@ -1006,7 +1006,7 @@ fn BackupAuthCredentialRequest_IssueDeterministic(
|
||||
|
||||
let response = request.issue(
|
||||
redemption_time.as_seconds(),
|
||||
receipt_level,
|
||||
backup_level.into_inner(),
|
||||
¶ms,
|
||||
*randomness,
|
||||
);
|
||||
@ -1025,7 +1025,6 @@ fn BackupAuthCredentialRequestContext_ReceiveResponse(
|
||||
context_bytes: &[u8],
|
||||
response_bytes: &[u8],
|
||||
params_bytes: &[u8],
|
||||
expected_receipt_level: u64,
|
||||
) -> Result<Vec<u8>, ZkGroupVerificationFailure> {
|
||||
let context = bincode::deserialize::<BackupAuthCredentialRequestContext>(context_bytes)
|
||||
.expect("should have been parsed previously");
|
||||
@ -1034,7 +1033,7 @@ fn BackupAuthCredentialRequestContext_ReceiveResponse(
|
||||
let params = bincode::deserialize::<GenericServerPublicParams>(params_bytes)
|
||||
.expect("should have been parsed previously");
|
||||
|
||||
let credential = context.receive(response, ¶ms, expected_receipt_level)?;
|
||||
let credential = context.receive(response, ¶ms)?;
|
||||
Ok(zkgroup::serialize(&credential))
|
||||
}
|
||||
|
||||
@ -1052,6 +1051,13 @@ fn BackupAuthCredential_GetBackupId(credential_bytes: &[u8]) -> [u8; 16] {
|
||||
credential.backup_id()
|
||||
}
|
||||
|
||||
#[bridge_fn]
|
||||
fn BackupAuthCredential_GetBackupLevel(credential_bytes: &[u8]) -> u8 {
|
||||
let credential = bincode::deserialize::<BackupAuthCredential>(credential_bytes)
|
||||
.expect("should have been parsed previously");
|
||||
credential.backup_level() as u8
|
||||
}
|
||||
|
||||
#[bridge_fn]
|
||||
fn BackupAuthCredential_PresentDeterministic(
|
||||
credential_bytes: &[u8],
|
||||
@ -1096,10 +1102,10 @@ fn BackupAuthCredentialPresentation_GetBackupId(presentation_bytes: &[u8]) -> [u
|
||||
}
|
||||
|
||||
#[bridge_fn(ffi = false, node = false)]
|
||||
fn BackupAuthCredentialPresentation_GetReceiptLevel(presentation_bytes: &[u8]) -> ReceiptLevel {
|
||||
fn BackupAuthCredentialPresentation_GetBackupLevel(presentation_bytes: &[u8]) -> u8 {
|
||||
let presentation = bincode::deserialize::<BackupAuthCredentialPresentation>(presentation_bytes)
|
||||
.expect("should have been parsed previously");
|
||||
presentation.receipt_level()
|
||||
presentation.backup_level() as u8
|
||||
}
|
||||
|
||||
#[bridge_fn]
|
||||
|
@ -7,5 +7,5 @@ mod auth_credential;
|
||||
|
||||
pub use auth_credential::{
|
||||
BackupAuthCredential, BackupAuthCredentialPresentation, BackupAuthCredentialRequest,
|
||||
BackupAuthCredentialRequestContext, BackupAuthCredentialResponse,
|
||||
BackupAuthCredentialRequestContext, BackupAuthCredentialResponse, BackupLevel,
|
||||
};
|
||||
|
@ -45,6 +45,41 @@ impl zkcredential::attributes::RevealedAttribute for BackupIdPoint {
|
||||
|
||||
const CREDENTIAL_LABEL: &[u8] = b"20231003_Signal_BackupAuthCredential";
|
||||
|
||||
// We make sure we serialize BackupLevel with plenty of room to expand to other
|
||||
// u64 values later. But since it fits in a byte today, we stick to just a u8
|
||||
// in the in-memory representation.
|
||||
#[derive(
|
||||
Copy,
|
||||
Clone,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialDefault,
|
||||
Debug,
|
||||
num_enum::TryFromPrimitive,
|
||||
)]
|
||||
#[serde(into = "u64", try_from = "u64")]
|
||||
#[repr(u8)]
|
||||
pub enum BackupLevel {
|
||||
#[partial_default]
|
||||
Messages = 200,
|
||||
Media = 201,
|
||||
}
|
||||
|
||||
impl From<BackupLevel> for u64 {
|
||||
fn from(backup_level: BackupLevel) -> Self {
|
||||
backup_level as u64
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u64> for BackupLevel {
|
||||
type Error = <BackupLevel as TryFrom<u8>>::Error;
|
||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||
BackupLevel::try_from(value as u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialDefault)]
|
||||
pub struct BackupAuthCredentialRequestContext {
|
||||
reserved: ReservedByte,
|
||||
@ -107,17 +142,17 @@ impl BackupAuthCredentialRequest {
|
||||
pub fn issue(
|
||||
&self,
|
||||
redemption_time: Timestamp,
|
||||
receipt_level: ReceiptLevel,
|
||||
backup_level: BackupLevel,
|
||||
params: &GenericServerSecretParams,
|
||||
randomness: RandomnessBytes,
|
||||
) -> BackupAuthCredentialResponse {
|
||||
BackupAuthCredentialResponse {
|
||||
reserved: Default::default(),
|
||||
redemption_time,
|
||||
receipt_level,
|
||||
backup_level,
|
||||
blinded_credential: zkcredential::issuance::IssuanceProofBuilder::new(CREDENTIAL_LABEL)
|
||||
.add_public_attribute(&redemption_time)
|
||||
.add_public_attribute(&receipt_level)
|
||||
.add_public_attribute(&(backup_level as u64))
|
||||
.add_blinded_revealed_attribute(&self.blinded_backup_id)
|
||||
.issue(¶ms.credential_key, &self.public_key, randomness),
|
||||
}
|
||||
@ -128,7 +163,7 @@ impl BackupAuthCredentialRequest {
|
||||
pub struct BackupAuthCredentialResponse {
|
||||
reserved: ReservedByte,
|
||||
redemption_time: Timestamp,
|
||||
receipt_level: ReceiptLevel,
|
||||
backup_level: BackupLevel,
|
||||
blinded_credential: zkcredential::issuance::blind::BlindedIssuanceProof,
|
||||
}
|
||||
|
||||
@ -137,23 +172,18 @@ impl BackupAuthCredentialRequestContext {
|
||||
self,
|
||||
response: BackupAuthCredentialResponse,
|
||||
params: &GenericServerPublicParams,
|
||||
expected_receipt_level: ReceiptLevel,
|
||||
) -> Result<BackupAuthCredential, ZkGroupVerificationFailure> {
|
||||
if response.redemption_time % SECONDS_PER_DAY != 0 {
|
||||
return Err(ZkGroupVerificationFailure);
|
||||
}
|
||||
|
||||
if response.receipt_level != expected_receipt_level {
|
||||
return Err(ZkGroupVerificationFailure);
|
||||
}
|
||||
|
||||
Ok(BackupAuthCredential {
|
||||
reserved: Default::default(),
|
||||
redemption_time: response.redemption_time,
|
||||
receipt_level: response.receipt_level,
|
||||
backup_level: response.backup_level,
|
||||
credential: zkcredential::issuance::IssuanceProofBuilder::new(CREDENTIAL_LABEL)
|
||||
.add_public_attribute(&response.redemption_time)
|
||||
.add_public_attribute(&expected_receipt_level)
|
||||
.add_public_attribute(&(response.backup_level as u64))
|
||||
.add_blinded_revealed_attribute(&self.blinded_backup_id)
|
||||
.verify(
|
||||
¶ms.credential_key,
|
||||
@ -170,7 +200,7 @@ impl BackupAuthCredentialRequestContext {
|
||||
pub struct BackupAuthCredential {
|
||||
reserved: ReservedByte,
|
||||
redemption_time: Timestamp,
|
||||
receipt_level: ReceiptLevel,
|
||||
backup_level: BackupLevel,
|
||||
credential: zkcredential::credentials::Credential,
|
||||
backup_id: [u8; 16],
|
||||
}
|
||||
@ -184,7 +214,7 @@ impl BackupAuthCredential {
|
||||
BackupAuthCredentialPresentation {
|
||||
version: Default::default(),
|
||||
redemption_time: self.redemption_time,
|
||||
receipt_level: self.receipt_level,
|
||||
backup_level: self.backup_level,
|
||||
backup_id: self.backup_id,
|
||||
proof: zkcredential::presentation::PresentationProofBuilder::new(CREDENTIAL_LABEL)
|
||||
.add_revealed_attribute(&BackupIdPoint::new(&self.backup_id))
|
||||
@ -195,12 +225,16 @@ impl BackupAuthCredential {
|
||||
pub fn backup_id(&self) -> [u8; 16] {
|
||||
self.backup_id
|
||||
}
|
||||
|
||||
pub fn backup_level(&self) -> BackupLevel {
|
||||
self.backup_level
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialDefault)]
|
||||
pub struct BackupAuthCredentialPresentation {
|
||||
version: ReservedByte,
|
||||
receipt_level: ReceiptLevel,
|
||||
backup_level: BackupLevel,
|
||||
redemption_time: Timestamp,
|
||||
proof: zkcredential::presentation::PresentationProof,
|
||||
backup_id: [u8; 16],
|
||||
@ -227,14 +261,14 @@ impl BackupAuthCredentialPresentation {
|
||||
|
||||
zkcredential::presentation::PresentationProofVerifier::new(CREDENTIAL_LABEL)
|
||||
.add_public_attribute(&self.redemption_time)
|
||||
.add_public_attribute(&self.receipt_level)
|
||||
.add_public_attribute(&(self.backup_level as u64))
|
||||
.add_revealed_attribute(&BackupIdPoint::new(&self.backup_id))
|
||||
.verify(&server_params.credential_key, &self.proof)
|
||||
.map_err(|_| ZkGroupVerificationFailure)
|
||||
}
|
||||
|
||||
pub fn receipt_level(&self) -> ReceiptLevel {
|
||||
self.receipt_level
|
||||
pub fn backup_level(&self) -> BackupLevel {
|
||||
self.backup_level
|
||||
}
|
||||
|
||||
pub fn backup_id(&self) -> [u8; 16] {
|
||||
@ -244,11 +278,11 @@ impl BackupAuthCredentialPresentation {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::backups::auth_credential::GenericServerSecretParams;
|
||||
use crate::backups::auth_credential::{BackupLevel, GenericServerSecretParams};
|
||||
use crate::backups::{
|
||||
BackupAuthCredential, BackupAuthCredentialPresentation, BackupAuthCredentialRequestContext,
|
||||
};
|
||||
use crate::{RandomnessBytes, Timestamp, RANDOMNESS_LEN, SECONDS_PER_DAY};
|
||||
use crate::{common, RandomnessBytes, Timestamp, RANDOMNESS_LEN, SECONDS_PER_DAY};
|
||||
|
||||
const DAY_ALIGNED_TIMESTAMP: Timestamp = 1681344000; // 2023-04-13 00:00:00 UTC
|
||||
const KEY: [u8; 32] = [0x42u8; 32];
|
||||
@ -262,8 +296,6 @@ mod tests {
|
||||
}
|
||||
|
||||
fn generate_credential(redemption_time: Timestamp) -> BackupAuthCredential {
|
||||
let receipt_level = 10;
|
||||
|
||||
// client generated materials; issuance request
|
||||
let request_context = BackupAuthCredentialRequestContext::new(&KEY, &ACI);
|
||||
let request = request_context.get_request();
|
||||
@ -271,7 +303,7 @@ mod tests {
|
||||
// server generated materials; issuance request -> issuance response
|
||||
let blinded_credential = request.issue(
|
||||
redemption_time,
|
||||
receipt_level,
|
||||
BackupLevel::Messages,
|
||||
&server_secret_params(),
|
||||
ISSUE_RAND,
|
||||
);
|
||||
@ -279,7 +311,7 @@ mod tests {
|
||||
// client generated materials; issuance response -> redemption request
|
||||
let server_public_params = server_secret_params().get_public_params();
|
||||
request_context
|
||||
.receive(blinded_credential, &server_public_params, receipt_level)
|
||||
.receive(blinded_credential, &server_public_params)
|
||||
.expect("credential should be valid")
|
||||
}
|
||||
|
||||
@ -341,7 +373,8 @@ mod tests {
|
||||
let valid_presentation =
|
||||
credential.present(&server_secret_params().get_public_params(), PRESENT_RAND);
|
||||
let invalid_presentation = BackupAuthCredentialPresentation {
|
||||
receipt_level: 999,
|
||||
// Credential was for BackupLevel::MESSAGES
|
||||
backup_level: BackupLevel::Media,
|
||||
..valid_presentation
|
||||
};
|
||||
invalid_presentation
|
||||
@ -353,29 +386,11 @@ mod tests {
|
||||
fn test_client_enforces_timestamp_granularity() {
|
||||
let redemption_time: Timestamp = DAY_ALIGNED_TIMESTAMP + 60 * 60; // not on a day boundary!
|
||||
|
||||
let request_context = BackupAuthCredentialRequestContext::new(&KEY, &ACI);
|
||||
let request = request_context.get_request();
|
||||
let blinded_credential =
|
||||
request.issue(redemption_time, 1, &server_secret_params(), ISSUE_RAND);
|
||||
assert!(
|
||||
request_context
|
||||
.receive(
|
||||
blinded_credential,
|
||||
&server_secret_params().get_public_params(),
|
||||
1
|
||||
)
|
||||
.is_err(),
|
||||
"client should require that timestamp is on a day boundary"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_enforces_receipt_level() {
|
||||
let request_context = BackupAuthCredentialRequestContext::new(&KEY, &ACI);
|
||||
let request = request_context.get_request();
|
||||
let blinded_credential = request.issue(
|
||||
DAY_ALIGNED_TIMESTAMP,
|
||||
1,
|
||||
redemption_time,
|
||||
BackupLevel::Messages,
|
||||
&server_secret_params(),
|
||||
ISSUE_RAND,
|
||||
);
|
||||
@ -384,10 +399,30 @@ mod tests {
|
||||
.receive(
|
||||
blinded_credential,
|
||||
&server_secret_params().get_public_params(),
|
||||
2
|
||||
)
|
||||
.is_err(),
|
||||
"client should require receipt level 2"
|
||||
"client should require that timestamp is on a day boundary"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_backup_level_serialization() {
|
||||
let messages_bytes = common::serialization::serialize(&BackupLevel::Messages);
|
||||
let media_byte = common::serialization::serialize(&BackupLevel::Media);
|
||||
assert_eq!(messages_bytes.len(), 8);
|
||||
assert_eq!(media_byte.len(), 8);
|
||||
|
||||
let messages_num: u64 =
|
||||
common::serialization::deserialize(&messages_bytes).expect("valid u64");
|
||||
let media_num: u64 = common::serialization::deserialize(&media_byte).expect("valid u64");
|
||||
assert_eq!(messages_num, 200);
|
||||
assert_eq!(media_num, 201);
|
||||
|
||||
let messages: BackupLevel =
|
||||
common::serialization::deserialize(&messages_bytes).expect("valid level");
|
||||
let media: BackupLevel =
|
||||
common::serialization::deserialize(&media_byte).expect("valid level");
|
||||
assert_eq!(messages, BackupLevel::Messages);
|
||||
assert_eq!(media, BackupLevel::Media);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
use zkgroup::{RandomnessBytes, ReceiptLevel, Timestamp, RANDOMNESS_LEN};
|
||||
use zkgroup::{RandomnessBytes, Timestamp, RANDOMNESS_LEN};
|
||||
|
||||
const DAY_ALIGNED_TIMESTAMP: Timestamp = 1681344000; // 2023-04-13 00:00:00 UTC
|
||||
|
||||
@ -21,7 +21,7 @@ fn test_backup_auth_request_response() {
|
||||
|
||||
// client receives in response to initial request
|
||||
let redemption_time: Timestamp = DAY_ALIGNED_TIMESTAMP; // client validates it's day-aligned
|
||||
let receipt_level: ReceiptLevel = 100; // client validates it's their expected receipt level
|
||||
let backup_level = zkgroup::backups::BackupLevel::Messages; // client validates it's a valid backup level
|
||||
|
||||
// client generated materials; issuance request
|
||||
let request_context =
|
||||
@ -33,7 +33,7 @@ fn test_backup_auth_request_response() {
|
||||
zkgroup::generic_server_params::GenericServerSecretParams::generate(randomness1);
|
||||
let blinded_credential = request.issue(
|
||||
redemption_time,
|
||||
receipt_level,
|
||||
backup_level,
|
||||
&server_secret_params,
|
||||
randomness2,
|
||||
);
|
||||
@ -41,9 +41,11 @@ fn test_backup_auth_request_response() {
|
||||
// client generated materials; issuance response -> redemption request
|
||||
let server_public_params = server_secret_params.get_public_params();
|
||||
let credential = request_context
|
||||
.receive(blinded_credential, &server_public_params, receipt_level)
|
||||
.receive(blinded_credential, &server_public_params)
|
||||
.expect("credential should be valid");
|
||||
|
||||
assert_eq!(credential.backup_level(), backup_level);
|
||||
|
||||
let presentation = credential.present(&server_public_params, randomness3);
|
||||
|
||||
// server verification of the credential presentation
|
||||
|
@ -40,4 +40,18 @@ public class BackupAuthCredential: ByteArray {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var backupLevel: BackupLevel {
|
||||
return failOnError {
|
||||
let rawValue = try withUnsafeBorrowedBuffer { contents in
|
||||
try invokeFnReturningInteger {
|
||||
signal_backup_auth_credential_get_backup_level($0, contents)
|
||||
}
|
||||
}
|
||||
guard let backupLevel = BackupLevel(rawValue: rawValue) else {
|
||||
throw SignalError.internalError("Invalid BackupLevel \(rawValue)")
|
||||
}
|
||||
return backupLevel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,19 +11,19 @@ public class BackupAuthCredentialRequest: ByteArray {
|
||||
try super.init(contents, checkValid: signal_backup_auth_credential_request_check_valid_contents)
|
||||
}
|
||||
|
||||
public func issueCredential(timestamp: Date, receiptLevel: UInt64, params: GenericServerSecretParams) -> BackupAuthCredentialResponse {
|
||||
public func issueCredential(timestamp: Date, backupLevel: BackupLevel, params: GenericServerSecretParams) -> BackupAuthCredentialResponse {
|
||||
return failOnError {
|
||||
self.issueCredential(timestamp: timestamp, receiptLevel: receiptLevel, params: params, randomness: try .generate())
|
||||
self.issueCredential(timestamp: timestamp, backupLevel: backupLevel, params: params, randomness: try .generate())
|
||||
}
|
||||
}
|
||||
|
||||
public func issueCredential(timestamp: Date, receiptLevel: UInt64, params: GenericServerSecretParams, randomness: Randomness) -> BackupAuthCredentialResponse {
|
||||
public func issueCredential(timestamp: Date, backupLevel: BackupLevel, params: GenericServerSecretParams, randomness: Randomness) -> BackupAuthCredentialResponse {
|
||||
return failOnError {
|
||||
try withUnsafeBorrowedBuffer { contents in
|
||||
try params.withUnsafeBorrowedBuffer { params in
|
||||
try randomness.withUnsafePointerToBytes { randomness in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_backup_auth_credential_request_issue_deterministic($0, contents, UInt64(timestamp.timeIntervalSince1970), receiptLevel, params, randomness)
|
||||
signal_backup_auth_credential_request_issue_deterministic($0, contents, UInt64(timestamp.timeIntervalSince1970), backupLevel.rawValue, params, randomness)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,12 +35,12 @@ public class BackupAuthCredentialRequestContext: ByteArray {
|
||||
}
|
||||
}
|
||||
|
||||
public func receive(_ response: BackupAuthCredentialResponse, params: GenericServerPublicParams, expectedReceiptLevel: UInt64) throws -> BackupAuthCredential {
|
||||
public func receive(_ response: BackupAuthCredentialResponse, params: GenericServerPublicParams) throws -> BackupAuthCredential {
|
||||
return try withUnsafeBorrowedBuffer { contents in
|
||||
try response.withUnsafeBorrowedBuffer { response in
|
||||
try params.withUnsafeBorrowedBuffer { params in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_backup_auth_credential_request_context_receive_response($0, contents, response, params, expectedReceiptLevel)
|
||||
signal_backup_auth_credential_request_context_receive_response($0, contents, response, params)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
12
swift/Sources/LibSignalClient/zkgroup/BackupLevel.swift
Normal file
12
swift/Sources/LibSignalClient/zkgroup/BackupLevel.swift
Normal file
@ -0,0 +1,12 @@
|
||||
//
|
||||
// Copyright 2024 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SignalFfi
|
||||
|
||||
public enum BackupLevel: UInt8 {
|
||||
// This must match the Rust version of the enum.
|
||||
case messages = 200, media = 201
|
||||
}
|
@ -1341,16 +1341,18 @@ SignalFfiError *signal_backup_auth_credential_request_context_get_request(Signal
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_request_check_valid_contents(SignalBorrowedBuffer request_bytes);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, uint64_t redemption_time, uint64_t receipt_level, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]);
|
||||
SignalFfiError *signal_backup_auth_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, uint64_t redemption_time, uint8_t backup_level, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer params_bytes, uint64_t expected_receipt_level);
|
||||
SignalFfiError *signal_backup_auth_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, SignalBorrowedBuffer params_bytes);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_check_valid_contents(SignalBorrowedBuffer params_bytes);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_get_backup_id(uint8_t (*out)[16], SignalBorrowedBuffer credential_bytes);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_get_backup_level(uint8_t *out, SignalBorrowedBuffer credential_bytes);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, SignalBorrowedBuffer server_params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes);
|
||||
|
@ -429,7 +429,7 @@ class ZKGroupTests: TestCaseBase {
|
||||
let aci = UUID(uuidString: "e74beed0-e70f-4cfd-abbb-7e3eb333bbac")!
|
||||
let serializedBackupID: [UInt8] = [0xE3, 0x92, 0x6F, 0x11, 0xDD, 0xD1, 0x43, 0xE6, 0xDD, 0x0F, 0x20, 0xBF, 0xCB, 0x08, 0x34, 0x9E]
|
||||
let serializedRequestCredential = Data(base64Encoded: "AISCxQa8OsFqphsQPxqtzJk5+jndpE3SJG6bfazQB3994Aersq2yNRgcARBoedBeoEfKIXdty6X7l6+TiPFAqDvojRSO8xaZOpKJOvWSDJIGn6EeMl2jOjx+IQg8d8M0AQ==")!
|
||||
let receiptLevel: UInt64 = 1
|
||||
let backupLevel = BackupLevel.messages
|
||||
|
||||
let context = BackupAuthCredentialRequestContext.create(backupKey: backupKey, aci: aci)
|
||||
let request = context.getRequest()
|
||||
@ -439,13 +439,14 @@ class ZKGroupTests: TestCaseBase {
|
||||
|
||||
let now = UInt64(Date().timeIntervalSince1970)
|
||||
let startOfDay = now - (now % SECONDS_PER_DAY)
|
||||
let response = request.issueCredential(timestamp: Date(timeIntervalSince1970: TimeInterval(startOfDay)), receiptLevel: receiptLevel, params: serverSecretParams, randomness: self.TEST_ARRAY_32_2)
|
||||
let credential = try context.receive(response, params: serverPublicParams, expectedReceiptLevel: receiptLevel)
|
||||
let response = request.issueCredential(timestamp: Date(timeIntervalSince1970: TimeInterval(startOfDay)), backupLevel: backupLevel, params: serverSecretParams, randomness: self.TEST_ARRAY_32_2)
|
||||
let credential = try context.receive(response, params: serverPublicParams)
|
||||
XCTAssertEqual(credential.backupID, serializedBackupID)
|
||||
XCTAssertEqual(credential.backupLevel, backupLevel)
|
||||
}
|
||||
|
||||
func testBackupAuthCredential() throws {
|
||||
let receiptLevel: UInt64 = 10
|
||||
let backupLevel = BackupLevel.messages
|
||||
|
||||
let serverSecretParams = GenericServerSecretParams.generate(randomness: self.TEST_ARRAY_32)
|
||||
let serverPublicParams = serverSecretParams.getPublicParams()
|
||||
@ -459,11 +460,11 @@ class ZKGroupTests: TestCaseBase {
|
||||
// Server
|
||||
let now = UInt64(Date().timeIntervalSince1970)
|
||||
let startOfDay = now - (now % SECONDS_PER_DAY)
|
||||
let response = request.issueCredential(timestamp: Date(timeIntervalSince1970: TimeInterval(startOfDay)), receiptLevel: receiptLevel, params: serverSecretParams, randomness: self.TEST_ARRAY_32_2)
|
||||
let response = request.issueCredential(timestamp: Date(timeIntervalSince1970: TimeInterval(startOfDay)), backupLevel: backupLevel, params: serverSecretParams, randomness: self.TEST_ARRAY_32_2)
|
||||
|
||||
// Client
|
||||
let credential = try context.receive(response, params: serverPublicParams, expectedReceiptLevel: receiptLevel)
|
||||
XCTAssertThrowsError(try context.receive(response, params: serverPublicParams, expectedReceiptLevel: receiptLevel + 1))
|
||||
let credential = try context.receive(response, params: serverPublicParams)
|
||||
XCTAssertEqual(backupLevel, credential.backupLevel)
|
||||
|
||||
let presentation = credential.present(serverParams: serverPublicParams, randomness: self.TEST_ARRAY_32_3)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user