Use strongly-typed pre-keys

This commit is contained in:
Jon Chambers
2023-06-09 10:08:49 -04:00
committed by GitHub
parent b27334b0ff
commit 17aa5d8e74
47 changed files with 805 additions and 719 deletions

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
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.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.ecc.ECPublicKey;
public class ECPublicKeyAdapter {
public static class Serializer extends JsonSerializer<ECPublicKey> {
@Override
public void serialize(final ECPublicKey ecPublicKey,
final JsonGenerator jsonGenerator,
final SerializerProvider serializers) throws IOException {
jsonGenerator.writeString(Base64.getEncoder().encodeToString(ecPublicKey.serialize()));
}
}
public static class Deserializer extends JsonDeserializer<ECPublicKey> {
@Override
public ECPublicKey deserialize(final JsonParser parser, final DeserializationContext context) throws IOException {
final byte[] ecPublicKeyBytes;
try {
ecPublicKeyBytes = Base64.getDecoder().decode(parser.getValueAsString());
} catch (final IllegalArgumentException e) {
throw new JsonParseException(parser, "Could not parse EC public key as a base64-encoded value", e);
}
try {
return new ECPublicKey(ecPublicKeyBytes);
} catch (final InvalidKeyException e) {
throw new JsonParseException(parser, "Could not interpret key bytes as an EC public key", e);
}
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParseException;
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 org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.kem.KEMPublicKey;
import java.io.IOException;
import java.util.Base64;
public class KEMPublicKeyAdapter {
public static class Serializer extends JsonSerializer<KEMPublicKey> {
@Override
public void serialize(final KEMPublicKey kemPublicKey,
final JsonGenerator jsonGenerator,
final SerializerProvider serializers) throws IOException {
jsonGenerator.writeString(Base64.getEncoder().encodeToString(kemPublicKey.serialize()));
}
}
public static class Deserializer extends JsonDeserializer<KEMPublicKey> {
@Override
public KEMPublicKey deserialize(final JsonParser parser, final DeserializationContext context) throws IOException {
final byte[] kemPublicKeyBytes;
try {
kemPublicKeyBytes = Base64.getDecoder().decode(parser.getValueAsString());
} catch (final IllegalArgumentException e) {
throw new JsonParseException(parser, "Could not parse KEM public key as a base64-encoded value", e);
}
try {
return new KEMPublicKey(kemPublicKeyBytes);
} catch (final InvalidKeyException e) {
throw new JsonParseException(parser, "Could not interpret key bytes as a KEM public key", e);
}
}
}
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Target({FIELD, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Constraint(validatedBy = {ValidPreKeyValidator.class})
@Documented
public @interface ValidPreKey {
public enum PreKeyType {
ECC,
KYBER
}
PreKeyType type();
String message() default "{org.whispersystems.textsecuregcm.util.ValidPreKey.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright 2013-2020 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.signal.libsignal.protocol.InvalidKeyException;
import org.signal.libsignal.protocol.ecc.Curve;
import org.signal.libsignal.protocol.kem.KEMPublicKey;
import org.whispersystems.textsecuregcm.entities.PreKey;
public class ValidPreKeyValidator implements ConstraintValidator<ValidPreKey, PreKey> {
private ValidPreKey.PreKeyType type;
@Override
public void initialize(ValidPreKey annotation) {
type = annotation.type();
}
@Override
public boolean isValid(PreKey value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
try {
switch (type) {
case ECC -> Curve.decodePoint(value.getPublicKey(), 0);
case KYBER -> new KEMPublicKey(value.getPublicKey());
}
} catch (IllegalArgumentException | InvalidKeyException e) {
return false;
}
return true;
}
}