Add option to omit full signer certificate from sealed sender certificates

This commit is contained in:
Jordan Rose
2026-01-13 11:43:28 -08:00
committed by GitHub
parent a1b1d051f5
commit 94c9d48da1
8 changed files with 161 additions and 119 deletions

View File

@@ -1072,7 +1072,7 @@ public class WhisperServerService extends Application<WhisperServerConfiguration
new CallLinkController(rateLimiters, callingGenericZkSecretParams),
new CallQualitySurveyController(callQualitySurveyManager),
new CertificateController(accountsManager, new CertificateGenerator(config.getDeliveryCertificate().certificate(),
config.getDeliveryCertificate().ecPrivateKey(), config.getDeliveryCertificate().expiresDays()),
config.getDeliveryCertificate().ecPrivateKey(), config.getDeliveryCertificate().expiresDays(), config.getDeliveryCertificate().embedSigner()),
zkAuthOperations, callingGenericZkSecretParams, clock),
new ChallengeController(accountsManager, rateLimitChallengeManager, challengeConstraintChecker),
new DeviceController(accountsManager, clientPublicKeysManager, rateLimiters, persistentTimer, config.getMaxDevices()),

View File

@@ -7,39 +7,48 @@ package org.whispersystems.textsecuregcm.auth;
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
import java.security.InvalidKeyException;
import java.util.concurrent.TimeUnit;
import org.signal.libsignal.protocol.ecc.ECPrivateKey;
import org.whispersystems.textsecuregcm.entities.MessageProtos.SenderCertificate;
import org.whispersystems.textsecuregcm.entities.MessageProtos.ServerCertificate;
import org.whispersystems.textsecuregcm.identity.IdentityType;
import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.util.UUIDUtil;
public class CertificateGenerator {
private final ECPrivateKey privateKey;
private final int expiresDays;
private final ECPrivateKey privateKey;
private final int expiresDays;
private final boolean embedSigner;
private final ServerCertificate serverCertificate;
private final int serverCertificateId;
public CertificateGenerator(byte[] serverCertificate, ECPrivateKey privateKey, int expiresDays)
throws InvalidProtocolBufferException
{
this.privateKey = privateKey;
this.expiresDays = expiresDays;
public CertificateGenerator(byte[] serverCertificate, ECPrivateKey privateKey, int expiresDays, boolean embedSigner)
throws InvalidProtocolBufferException {
this.privateKey = privateKey;
this.expiresDays = expiresDays;
this.embedSigner = embedSigner;
this.serverCertificate = ServerCertificate.parseFrom(serverCertificate);
this.serverCertificateId = ServerCertificate.Certificate
.parseFrom(this.serverCertificate.getCertificate())
.getId();
}
public byte[] createFor(final Account account, final byte deviceId, boolean includeE164) throws InvalidKeyException {
public byte[] createFor(final Account account, final byte deviceId, boolean includeE164) {
SenderCertificate.Certificate.Builder builder = SenderCertificate.Certificate.newBuilder()
.setSenderDevice(Math.toIntExact(deviceId))
.setExpires(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(expiresDays))
.setIdentityKey(ByteString.copyFrom(account.getIdentityKey(IdentityType.ACI).serialize()))
.setSigner(serverCertificate)
.setSenderUuid(account.getUuid().toString());
.setSenderUuid(UUIDUtil.toByteString(account.getUuid()));
if (includeE164) {
builder.setSender(account.getNumber());
builder.setSenderE164(account.getNumber());
}
if (embedSigner) {
builder.setSignerCertificate(serverCertificate);
} else {
builder.setSignerId(serverCertificateId);
}
byte[] certificate = builder.build().toByteArray();
@@ -47,10 +56,10 @@ public class CertificateGenerator {
signature = privateKey.calculateSignature(certificate);
return SenderCertificate.newBuilder()
.setCertificate(ByteString.copyFrom(certificate))
.setSignature(ByteString.copyFrom(signature))
.build()
.toByteArray();
.setCertificate(ByteString.copyFrom(certificate))
.setSignature(ByteString.copyFrom(signature))
.build()
.toByteArray();
}
}

View File

@@ -14,7 +14,8 @@ import org.whispersystems.textsecuregcm.util.ExactlySize;
public record UnidentifiedDeliveryConfiguration(@NotNull @NotEmpty byte[] certificate,
@ExactlySize(32) SecretBytes privateKey,
int expiresDays) {
int expiresDays,
boolean embedSigner) {
public ECPrivateKey ecPrivateKey() throws InvalidKeyException {
return new ECPrivateKey(privateKey.value());
}