diff --git a/java/java/src/main/java/org/signal/internal/Native.java b/java/java/src/main/java/org/signal/internal/Native.java index 21dfc225c..21972530b 100644 --- a/java/java/src/main/java/org/signal/internal/Native.java +++ b/java/java/src/main/java/org/signal/internal/Native.java @@ -214,4 +214,12 @@ public final class Native { public static native byte[] SignedPreKeyRecord_GetSignature(long handle); public static native long SignedPreKeyRecord_GetTimestamp(long handle); public static native long SignedPreKeyRecord_New(int id, long timestamp, long pubKeyHandle, long privKeyHandle, byte[] signature); + + public static native long UnidentifiedSenderMessageContent_Deserialize(byte[] data); + public static native void UnidentifiedSenderMessageContent_Destroy(long handle); + public static native byte[] UnidentifiedSenderMessageContent_GetContents(long handle); + public static native int UnidentifiedSenderMessageContent_GetMsgType(long handle); + public static native long UnidentifiedSenderMessageContent_GetSenderCert(long handle); + public static native byte[] UnidentifiedSenderMessageContent_GetSerialized(long handle); + public static native long UnidentifiedSenderMessageContent_New(int msgType, long sender, byte[] contents); } diff --git a/java/java/src/main/java/org/signal/libsignal/metadata/protocol/UnidentifiedSenderMessageContent.java b/java/java/src/main/java/org/signal/libsignal/metadata/protocol/UnidentifiedSenderMessageContent.java index 24656f465..cca98cd26 100644 --- a/java/java/src/main/java/org/signal/libsignal/metadata/protocol/UnidentifiedSenderMessageContent.java +++ b/java/java/src/main/java/org/signal/libsignal/metadata/protocol/UnidentifiedSenderMessageContent.java @@ -1,84 +1,46 @@ package org.signal.libsignal.metadata.protocol; - -import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; +import org.signal.client.internal.Native; import org.signal.libsignal.metadata.InvalidMetadataMessageException; -import org.signal.libsignal.metadata.SignalProtos; import org.signal.libsignal.metadata.certificate.InvalidCertificateException; import org.signal.libsignal.metadata.certificate.SenderCertificate; -import org.whispersystems.libsignal.InvalidMessageException; -import org.whispersystems.libsignal.protocol.CiphertextMessage; public class UnidentifiedSenderMessageContent { - private final int type; - private final SenderCertificate senderCertificate; - private final byte[] content; - private final byte[] serialized; + private final long handle; + + @Override + protected void finalize() { + Native.UnidentifiedSenderMessageContent_Destroy(this.handle); + } public UnidentifiedSenderMessageContent(byte[] serialized) throws InvalidMetadataMessageException, InvalidCertificateException { try { - SignalProtos.UnidentifiedSenderMessage.Message message = SignalProtos.UnidentifiedSenderMessage.Message.parseFrom(serialized); - - if (!message.hasType() || !message.hasSenderCertificate() || !message.hasContent()) { - throw new InvalidMetadataMessageException("Missing fields"); - } - - switch (message.getType()) { - case MESSAGE: this.type = CiphertextMessage.WHISPER_TYPE; break; - case PREKEY_MESSAGE: this.type = CiphertextMessage.PREKEY_TYPE; break; - default: throw new InvalidMetadataMessageException("Unknown type: " + message.getType().getNumber()); - } - - this.senderCertificate = new SenderCertificate(message.getSenderCertificate().toByteArray()); - this.content = message.getContent().toByteArray(); - this.serialized = serialized; - } catch (InvalidProtocolBufferException e) { + this.handle = Native.UnidentifiedSenderMessageContent_Deserialize(serialized); + } catch (Exception e) { throw new InvalidMetadataMessageException(e); } } public UnidentifiedSenderMessageContent(int type, SenderCertificate senderCertificate, byte[] content) { - try { - this.serialized = SignalProtos.UnidentifiedSenderMessage.Message.newBuilder() - .setType(SignalProtos.UnidentifiedSenderMessage.Message.Type.valueOf(getProtoType(type))) - .setSenderCertificate(SignalProtos.SenderCertificate.parseFrom(senderCertificate.getSerialized())) - .setContent(ByteString.copyFrom(content)) - .build() - .toByteArray(); - - this.type = type; - this.senderCertificate = senderCertificate; - this.content = content; - } catch (InvalidProtocolBufferException e) { - throw new AssertionError(e); - } + this.handle = Native.UnidentifiedSenderMessageContent_New(type, senderCertificate.nativeHandle(), content); } public int getType() { - return type; + return Native.UnidentifiedSenderMessageContent_GetMsgType(this.handle); } public SenderCertificate getSenderCertificate() { - return senderCertificate; + return new SenderCertificate(Native.UnidentifiedSenderMessageContent_GetSenderCert(this.handle)); } public byte[] getContent() { - return content; + return Native.UnidentifiedSenderMessageContent_GetContents(this.handle); } public byte[] getSerialized() { - return serialized; - } - - private int getProtoType(int type) { - switch (type) { - case CiphertextMessage.WHISPER_TYPE: return SignalProtos.UnidentifiedSenderMessage.Message.Type.MESSAGE_VALUE; - case CiphertextMessage.PREKEY_TYPE: return SignalProtos.UnidentifiedSenderMessage.Message.Type.PREKEY_MESSAGE_VALUE; - default: throw new AssertionError(type); - } + return Native.UnidentifiedSenderMessageContent_GetSerialized(this.handle); } } diff --git a/rust/bridge/jni/src/lib.rs b/rust/bridge/jni/src/lib.rs index f53725e04..907767dbb 100644 --- a/rust/bridge/jni/src/lib.rs +++ b/rust/bridge/jni/src/lib.rs @@ -1699,6 +1699,46 @@ pub unsafe extern "C" fn Java_org_signal_client_internal_Native_SenderCertificat let cert = native_handle_cast::(cert)?; let key = native_handle_cast::(key)?; let time = jlong_to_u64(time)?; - Ok(cert.validate(key, time)? as jboolean) + let valid = cert.validate(key, time)?; + Ok(valid as jboolean) + }) +} + +// UnidentifiedSenderMessageContent +jni_fn_destroy!(Java_org_signal_client_internal_Native_UnidentifiedSenderMessageContent_1Destroy destroys UnidentifiedSenderMessageContent); +jni_fn_deserialize!(Java_org_signal_client_internal_Native_UnidentifiedSenderMessageContent_1Deserialize is UnidentifiedSenderMessageContent::deserialize); + +jni_fn_get_jint!(Java_org_signal_client_internal_Native_UnidentifiedSenderMessageContent_1GetMsgType(UnidentifiedSenderMessageContent) using + |m: &UnidentifiedSenderMessageContent| Ok(m.msg_type()? as u32)); + +jni_fn_get_jbytearray!(Java_org_signal_client_internal_Native_UnidentifiedSenderMessageContent_1GetSerialized(UnidentifiedSenderMessageContent) using UnidentifiedSenderMessageContent::serialized); +jni_fn_get_jbytearray!(Java_org_signal_client_internal_Native_UnidentifiedSenderMessageContent_1GetContents(UnidentifiedSenderMessageContent) using UnidentifiedSenderMessageContent::contents); + +jni_fn_get_new_boxed_obj!(Java_org_signal_client_internal_Native_UnidentifiedSenderMessageContent_1GetSenderCert(SenderCertificate) from UnidentifiedSenderMessageContent, + |s: &UnidentifiedSenderMessageContent| Ok(s.sender()?.clone())); + +#[no_mangle] +pub unsafe extern "C" fn Java_org_signal_client_internal_Native_UnidentifiedSenderMessageContent_1New( + env: JNIEnv, + _class: JClass, + msg_type: jint, + sender: ObjectHandle, + contents: jbyteArray, +) -> ObjectHandle { + run_ffi_safe(&env, || { + let sender = native_handle_cast::(sender)?; + let contents = env.convert_byte_array(contents)?; + let msg_type = match msg_type { + 1 => Ok(1u8), + 2 => Ok(2u8), + 3 => Ok(1u8), + x => Err(SignalJniError::IntegerOverflow(format!( + "invalid msg_type argument {}", + x + ))), + }?; + + let usmc = UnidentifiedSenderMessageContent::new(msg_type, sender.clone(), contents)?; + box_object::(Ok(usmc)) }) } diff --git a/rust/protocol/src/lib.rs b/rust/protocol/src/lib.rs index 4ee1574f5..3a2a476e6 100644 --- a/rust/protocol/src/lib.rs +++ b/rust/protocol/src/lib.rs @@ -45,7 +45,7 @@ pub use { are_we_alice, initialize_alice_session, initialize_bob_session, AliceSignalProtocolParameters, BobSignalProtocolParameters, ChainKey, MessageKeys, RootKey, }, - sealed_sender::{SenderCertificate, ServerCertificate}, + sealed_sender::{SenderCertificate, ServerCertificate, UnidentifiedSenderMessageContent}, sender_keys::{ SenderChainKey, SenderKeyName, SenderKeyRecord, SenderKeyState, SenderMessageKey, }, diff --git a/rust/protocol/src/sealed_sender.rs b/rust/protocol/src/sealed_sender.rs index 850789357..83d7f44b6 100644 --- a/rust/protocol/src/sealed_sender.rs +++ b/rust/protocol/src/sealed_sender.rs @@ -287,3 +287,79 @@ impl SenderCertificate { Ok(&self.signature) } } + +pub struct UnidentifiedSenderMessageContent { + serialized: Vec, + contents: Vec, + sender: SenderCertificate, + msg_type: u8, +} + +impl UnidentifiedSenderMessageContent { + pub fn deserialize(data: &[u8]) -> Result { + let pb = proto::sealed_sender::unidentified_sender_message::Message::decode(data)?; + + let msg_type = pb + .r#type + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let sender = pb + .sender_certificate + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + let contents = pb + .content + .ok_or(SignalProtocolError::InvalidProtobufEncoding)?; + + let msg_type = match msg_type { + 1 => Ok(3), + 2 => Ok(2), + 3 => Ok(3), + _ => Err(SignalProtocolError::InvalidProtobufEncoding), + }?; + + let sender = SenderCertificate::from_protobuf(&sender)?; + + let serialized = data.to_vec(); + + Ok(Self { + serialized, + contents, + sender, + msg_type, + }) + } + + pub fn new(msg_type: u8, sender: SenderCertificate, contents: Vec) -> Result { + let msg = proto::sealed_sender::unidentified_sender_message::Message { + content: Some(contents.clone()), + r#type: Some(msg_type as _), + sender_certificate: Some(sender.to_protobuf()?), + }; + + let mut serialized = vec![]; + msg.encode(&mut serialized)?; + + // serialize it + Ok(Self { + msg_type, + sender, + contents, + serialized, + }) + } + + pub fn msg_type(&self) -> Result { + Ok(self.msg_type) + } + + pub fn sender(&self) -> Result<&SenderCertificate> { + Ok(&self.sender) + } + + pub fn contents(&self) -> Result<&[u8]> { + Ok(&self.contents) + } + + pub fn serialized(&self) -> Result<&[u8]> { + Ok(&self.serialized) + } +}