[Fix] Harden MTP codec, transport, and SDK security

This commit is contained in:
Alex Emmet 2026-08-18 20:57:45 +02:00
commit a7e804c603
No known key found for this signature in database
73 changed files with 11892 additions and 5756 deletions

View file

@ -3,8 +3,9 @@ use std::time::{Duration, Instant};
use mtp::client::MTPConnection;
use mtp::codec::{
CommunicationType, DataType, DataValue, ProtectionPolicy, ProtectedMessageBuilder,
ProtectionPurpose, SealedRelayBuilder, SignaturePolicy, TypeMap, open_relay_content,
open_relay_metadata,
ProtectionPurpose, SealedRelayBuilder, SignaturePolicy, TypeMap,
open_relay_content_with_limits_without_replay,
open_relay_metadata_without_replay,
};
use mtp::common::unix_time_millis;
use mtp::crypto::{Ed25519Signer, Keyring, PublicKeyBundle};
@ -159,7 +160,7 @@ pub async fn send_sealed_relay(
return Err("relay forwarding changed the sealed-sender boundary".into());
}
let metadata = open_relay_metadata(
let metadata = open_relay_metadata_without_replay(
&forwarded,
&final_recipient_keyring,
signer_id,
@ -169,7 +170,7 @@ pub async fn send_sealed_relay(
let application_metadata = metadata
.metadata()
.ok_or("forwarded relay metadata was missing")?;
let content = open_relay_content(
let content = open_relay_content_with_limits_without_replay(
&metadata,
&final_recipient_keyring,
&signer_keyring.public_key_bundle(),

View file

@ -17,14 +17,22 @@ fn main() -> Result<(), files::FileError> {
/* Read both back to confirm the files round-trip through the on-disk format. */
let loaded_keyring = load_keyring_raw(&keyring_path)?;
let loaded_bundle = load_public_key_bundle(&bundle_path)?;
assert_eq!(keyring.to_bytes(), loaded_keyring.to_bytes());
assert_eq!(keyring.try_to_bytes()?, loaded_keyring.try_to_bytes()?);
let bundle_bytes = keyring.public_key_bundle().try_as_bytes()?;
let loaded_bundle_bytes = loaded_bundle.try_as_bytes()?;
assert_eq!(
keyring.public_key_bundle().as_bytes(),
loaded_bundle.as_bytes()
bundle_bytes,
loaded_bundle_bytes
);
println!(
"\nPrivateKeyRing (base64):\n{}",
keyring.try_to_base64()?
);
println!("\nPrivateKeyRing (base64):\n{}", keyring.to_base64());
println!("\nPublicKeyBundle (base64):\n{}", loaded_bundle.to_base64());
println!(
"\nPublicKeyBundle (base64):\n{}",
loaded_bundle.try_to_base64()?
);
println!("Wrote keyring -> {}", keyring_path.display());
println!("Wrote bundle -> {}", bundle_path.display());

View file

@ -3,7 +3,9 @@ use std::collections::HashMap;
use mtp::codec::{
CommunicationType, CommunicationValue, DataType, DataTypeId, DataValue, InMemoryReplayGuard,
ProtectedOpenOptions, ProtectionPolicy, ProtectionPurpose, SignaturePolicy, TypeMap,
forward_relay_frame, open_protected_with, open_relay_content, open_relay_metadata_with,
forward_relay_frame, open_protected_with_checked,
open_relay_content_with_limits_without_replay,
open_relay_metadata_with_checked,
};
use mtp::crypto::{Keyring, PublicKeyBundle};
@ -65,7 +67,7 @@ fn process_direct_protected(
));
}
let opened = open_protected_with(
let opened = open_protected_with_checked(
msg,
std::slice::from_ref(&host_keyring),
None,
@ -76,7 +78,7 @@ fn process_direct_protected(
ProtectionPurpose::from(DIRECT_ENCRYPTION_PURPOSE),
SIGNATURE_POLICY,
),
Some(accepted_messages),
accepted_messages,
)
.map_err(|e| format!("direct protected message could not be authenticated: {e}"))?;
let signer_id = opened.signer_id;
@ -133,7 +135,7 @@ fn process_sealed_relay(
));
}
let metadata = open_relay_metadata_with(
let metadata = open_relay_metadata_with_checked(
msg,
std::slice::from_ref(&host_keyring),
None,
@ -141,7 +143,7 @@ fn process_sealed_relay(
resolve_signer_key(signer_id, registered_clients).map(|key| vec![key])
},
SIGNATURE_POLICY,
Some(accepted_messages),
accepted_messages,
)
.map_err(|e| format!("metadata relay could not authenticate metadata: {e}"))?;
println!(
@ -160,7 +162,7 @@ fn process_sealed_relay(
.len()
);
let content_result = open_relay_content(
let content_result = open_relay_content_with_limits_without_replay(
&metadata,
host_keyring,
&resolve_signer_key(metadata.signer_id(), registered_clients)

View file

@ -27,7 +27,7 @@ pub async fn export_host_public_keys(
save_public_key_bundle(&bundle, "host.mpkb")?;
/* The web client fetches the bundle as hex over HTTP. */
let bundle_hex = hex::encode(bundle.as_bytes());
let bundle_hex = hex::encode(bundle.try_as_bytes()?);
fs::write("host_public_key_bundle.hex", &bundle_hex).await?;
fs::create_dir_all("web-client/public").await?;
fs::write("web-client/public/host_public_key_bundle.hex", &bundle_hex).await?;

View file

@ -111,8 +111,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
}) as Pin<Box<dyn Future<Output = u64> + Send>>
};
let decrypt_keyring_bytes = host_keyring.try_to_bytes()?;
let decrypt_keyring = Arc::new(
match mtp::crypto::Keyring::from_bytes(&host_keyring.to_bytes()) {
match mtp::crypto::Keyring::from_bytes(&decrypt_keyring_bytes) {
Ok(keyring) => keyring,
Err(e) => {
return Err(format!("failed to re-load host keyring for decryption: {e}").into());