Add SenderCertificate and ServerCertificate

This commit is contained in:
Jack Lloyd
2020-11-10 15:59:47 -05:00
parent 57db5dcb5e
commit 507629ff0d
14 changed files with 617 additions and 124 deletions

View File

@@ -136,6 +136,19 @@ public final class Native {
public static native boolean ScannableFingerprint_Compare(byte[] fprint1, byte[] fprint2);
public static native long SenderCertificate_Deserialize(byte[] data);
public static native void SenderCertificate_Destroy(long handle);
public static native byte[] SenderCertificate_GetCertificate(long handle);
public static native int SenderCertificate_GetDeviceId(long handle);
public static native long SenderCertificate_GetExpiration(long handle);
public static native long SenderCertificate_GetKey(long handle);
public static native String SenderCertificate_GetSenderE164(long handle);
public static native String SenderCertificate_GetSenderUuid(long handle);
public static native byte[] SenderCertificate_GetSerialized(long handle);
public static native long SenderCertificate_GetServerCertificate(long handle);
public static native byte[] SenderCertificate_GetSignature(long handle);
public static native boolean SenderCertificate_Validate(long cert, long key, long time);
public static native long SenderKeyDistributionMessage_Deserialize(byte[] data);
public static native void SenderKeyDistributionMessage_Destroy(long handle);
public static native byte[] SenderKeyDistributionMessage_GetChainKey(long handle);
@@ -165,6 +178,14 @@ public final class Native {
public static native byte[] SenderKeyRecord_GetSerialized(long handle);
public static native long SenderKeyRecord_New();
public static native long ServerCertificate_Deserialize(byte[] data);
public static native void ServerCertificate_Destroy(long handle);
public static native byte[] ServerCertificate_GetCertificate(long handle);
public static native long ServerCertificate_GetKey(long handle);
public static native int ServerCertificate_GetKeyId(long handle);
public static native byte[] ServerCertificate_GetSerialized(long handle);
public static native byte[] ServerCertificate_GetSignature(long handle);
public static native void SessionBuilder_ProcessPreKeyBundle(long bundle, long protocolAddress, SessionStore sessionStore, IdentityKeyStore identityKeyStore);
public static native byte[] SessionCipher_DecryptPreKeySignalMessage(long message, long protocolAddress, SessionStore sessionStore, IdentityKeyStore identityKeyStore, PreKeyStore prekeyStore, SignedPreKeyStore signedPrekeyStore);

View File

@@ -1,20 +1,12 @@
package org.signal.libsignal.metadata.certificate;
import org.signal.client.internal.Native;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.ecc.Curve;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import java.util.HashSet;
import java.util.Set;
import org.whispersystems.libsignal.InvalidKeyException;
public class CertificateValidator {
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private static final Set<Integer> REVOKED = new HashSet<Integer>() {{
}};
private final ECPublicKey trustRoot;
public CertificateValidator(ECPublicKey trustRoot) {
@@ -23,17 +15,10 @@ public class CertificateValidator {
public void validate(SenderCertificate certificate, long validationTime) throws InvalidCertificateException {
try {
ServerCertificate serverCertificate = certificate.getSigner();
validate(serverCertificate);
if (!Curve.verifySignature(serverCertificate.getKey(), certificate.getCertificate(), certificate.getSignature())) {
throw new InvalidCertificateException("Signature failed");
}
if (validationTime > certificate.getExpiration()) {
throw new InvalidCertificateException("Certificate is expired");
}
} catch (InvalidKeyException e) {
if (!Native.SenderCertificate_Validate(certificate.nativeHandle(), trustRoot.nativeHandle(), validationTime)) {
throw new InvalidCertificateException("Validation failed");
}
} catch (Exception e) {
throw new InvalidCertificateException(e);
}
}
@@ -44,13 +29,8 @@ public class CertificateValidator {
if (!Curve.verifySignature(trustRoot, certificate.getCertificate(), certificate.getSignature())) {
throw new InvalidCertificateException("Signature failed");
}
if (REVOKED.contains(certificate.getKeyId())) {
throw new InvalidCertificateException("Server certificate has been revoked");
}
} catch (InvalidKeyException e) {
throw new InvalidCertificateException(e);
}
}
}

View File

@@ -1,100 +1,73 @@
package org.signal.libsignal.metadata.certificate;
import org.signal.client.internal.Native;
import com.google.protobuf.InvalidProtocolBufferException;
import org.signal.libsignal.metadata.SignalProtos;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.ecc.Curve;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.util.guava.Optional;
public class SenderCertificate {
private long handle;
private final ServerCertificate signer;
private final ECPublicKey key;
private final int senderDeviceId;
private final Optional<String> senderUuid;
private final Optional<String> senderE164;
private final long expiration;
@Override
protected void finalize() {
Native.SenderCertificate_Destroy(this.handle);
}
private final byte[] serialized;
private final byte[] certificate;
private final byte[] signature;
public long nativeHandle() {
return this.handle;
}
public SenderCertificate(byte[] serialized) throws InvalidCertificateException {
try {
SignalProtos.SenderCertificate wrapper = SignalProtos.SenderCertificate.parseFrom(serialized);
if (!wrapper.hasSignature() || !wrapper.hasCertificate()) {
throw new InvalidCertificateException("Missing fields");
}
SignalProtos.SenderCertificate.Certificate certificate = SignalProtos.SenderCertificate.Certificate.parseFrom(wrapper.getCertificate());
if (!certificate.hasSigner() ||
!certificate.hasIdentityKey() ||
!certificate.hasSenderDevice() ||
!certificate.hasExpires() ||
(!certificate.hasSenderUuid() && !certificate.hasSenderE164()))
{
throw new InvalidCertificateException("Missing fields");
}
this.signer = new ServerCertificate(certificate.getSigner().toByteArray());
this.key = Curve.decodePoint(certificate.getIdentityKey().toByteArray(), 0);
this.senderUuid = certificate.hasSenderUuid() ? Optional.of(certificate.getSenderUuid()) : Optional.<String>absent();
this.senderE164 = certificate.hasSenderE164() ? Optional.of(certificate.getSenderE164()) : Optional.<String>absent();
this.senderDeviceId = certificate.getSenderDevice();
this.expiration = certificate.getExpires();
this.serialized = serialized;
this.certificate = wrapper.getCertificate().toByteArray();
this.signature = wrapper.getSignature().toByteArray();
} catch (InvalidProtocolBufferException | InvalidKeyException e) {
handle = Native.SenderCertificate_Deserialize(serialized);
} catch (Exception e) {
throw new InvalidCertificateException(e);
}
}
public SenderCertificate(long handle) {
this.handle = handle;
}
public ServerCertificate getSigner() {
return signer;
return new ServerCertificate(Native.SenderCertificate_GetServerCertificate(this.handle));
}
public ECPublicKey getKey() {
return key;
return new ECPublicKey(Native.SenderCertificate_GetKey(this.handle));
}
public int getSenderDeviceId() {
return senderDeviceId;
return Native.SenderCertificate_GetDeviceId(this.handle);
}
public Optional<String> getSenderUuid() {
return senderUuid;
return Optional.fromNullable(Native.SenderCertificate_GetSenderUuid(this.handle));
}
public Optional<String> getSenderE164() {
return senderE164;
return Optional.fromNullable(Native.SenderCertificate_GetSenderE164(this.handle));
}
public String getSender() {
return senderE164.or(senderUuid).orNull();
return getSenderE164().or(getSenderUuid()).orNull();
}
public long getExpiration() {
return expiration;
return Native.SenderCertificate_GetExpiration(this.handle);
}
public byte[] getSerialized() {
return serialized;
return Native.SenderCertificate_GetSerialized(this.handle);
}
public byte[] getCertificate() {
return certificate;
return Native.SenderCertificate_GetCertificate(this.handle);
}
public byte[] getSignature() {
return signature;
return Native.SenderCertificate_GetSignature(this.handle);
}
}

View File

@@ -1,64 +1,49 @@
package org.signal.libsignal.metadata.certificate;
import org.signal.client.internal.Native;
import com.google.protobuf.InvalidProtocolBufferException;
import org.signal.libsignal.metadata.SignalProtos;
import org.whispersystems.libsignal.ecc.ECPublicKey;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.libsignal.ecc.Curve;
import org.whispersystems.libsignal.InvalidMessageException;
import org.whispersystems.libsignal.ecc.ECPublicKey;
public class ServerCertificate {
private final long handle;
private final int keyId;
private final ECPublicKey key;
@Override
protected void finalize() {
Native.ServerCertificate_Destroy(this.handle);
}
private final byte[] serialized;
private final byte[] certificate;
private final byte[] signature;
public ServerCertificate(long handle) {
this.handle = handle;
}
public ServerCertificate(byte[] serialized) throws InvalidCertificateException {
try {
SignalProtos.ServerCertificate wrapper = SignalProtos.ServerCertificate.parseFrom(serialized);
if (!wrapper.hasCertificate() || !wrapper.hasSignature()) {
throw new InvalidCertificateException("Missing fields");
}
SignalProtos.ServerCertificate.Certificate certificate = SignalProtos.ServerCertificate.Certificate.parseFrom(wrapper.getCertificate());
if (!certificate.hasId() || !certificate.hasKey()) {
throw new InvalidCertificateException("Missing fields");
}
this.keyId = certificate.getId();
this.key = Curve.decodePoint(certificate.getKey().toByteArray(), 0);
this.serialized = serialized;
this.certificate = wrapper.getCertificate().toByteArray();
this.signature = wrapper.getSignature().toByteArray();
} catch (InvalidProtocolBufferException | InvalidKeyException e) {
this.handle = Native.ServerCertificate_Deserialize(serialized);
} catch (Exception e) {
throw new InvalidCertificateException(e);
}
}
public int getKeyId() {
return keyId;
return Native.ServerCertificate_GetKeyId(this.handle);
}
public ECPublicKey getKey() {
return key;
return new ECPublicKey(Native.ServerCertificate_GetKey(this.handle));
}
public byte[] getSerialized() {
return serialized;
return Native.ServerCertificate_GetSerialized(this.handle);
}
public byte[] getCertificate() {
return certificate;
return Native.ServerCertificate_GetCertificate(this.handle);
}
public byte[] getSignature() {
return signature;
return Native.ServerCertificate_GetSignature(this.handle);
}
}