Merge
Crypto WASM TESTS
This commit is contained in:
parent
2a00bb35e7
commit
687e6f9642
49 changed files with 6272 additions and 366 deletions
|
|
@ -324,8 +324,7 @@ impl CommunicationValue {
|
|||
#[cfg(feature = "crypto")]
|
||||
let frame_signature = if is_signed {
|
||||
let alg = cursor.read_u8().map_err(|_| CodecError::InvalidEncoding)?;
|
||||
let sig_len =
|
||||
SigAlgorithm::length(alg).ok_or(CodecError::InvalidEncoding)?;
|
||||
let sig_len = SigAlgorithm::length(alg).ok_or(CodecError::InvalidEncoding)?;
|
||||
let mut sig = vec![0u8; sig_len];
|
||||
cursor
|
||||
.read_exact(&mut sig)
|
||||
|
|
@ -389,11 +388,7 @@ impl CommunicationValue {
|
|||
* signature before the data payload.
|
||||
*/
|
||||
#[cfg(feature = "crypto")]
|
||||
pub fn sign_frame(
|
||||
&mut self,
|
||||
algorithm: u8,
|
||||
signer: &impl SignatureScheme,
|
||||
) -> Option<()> {
|
||||
pub fn sign_frame(&mut self, algorithm: u8, signer: &impl SignatureScheme) -> Option<()> {
|
||||
let signed_payload = self.build_signed_payload().ok()?;
|
||||
let sig = signer.sign(&signed_payload).ok()?;
|
||||
self.frame_signature = Some((algorithm, sig));
|
||||
|
|
|
|||
|
|
@ -151,10 +151,17 @@ impl DataValue {
|
|||
|
||||
const KIND_NULL: u8 = 0xFF;
|
||||
|
||||
/// Smallest possible encoded entry, used to cap pre-reservation when
|
||||
/// decoding containers/arrays so a small frame cannot force a huge
|
||||
/// allocation from an attacker-controlled count. A bool/null entry in a
|
||||
/// container is 3 bytes (1 kind + 2 key); a bare value in an array is 1
|
||||
/// byte, so 1 is the safe lower bound shared by both.
|
||||
const MIN_ENTRY_BYTES: usize = 1;
|
||||
|
||||
pub fn container_from_map(map: &BTreeMap<DataTypeId, DataValue>) -> DataValue {
|
||||
let mut container = Vec::new();
|
||||
for (key, value) in map {
|
||||
container.push((key.clone(), value.clone()));
|
||||
container.push((*key, value.clone()));
|
||||
}
|
||||
DataValue::Container(container)
|
||||
}
|
||||
|
|
@ -407,7 +414,7 @@ impl DataValue {
|
|||
DataValue::Container(c) => {
|
||||
let mut out = BTreeMap::new();
|
||||
for (k, v) in c {
|
||||
out.insert(k.clone(), v.clone());
|
||||
out.insert(*k, v.clone());
|
||||
}
|
||||
Some(out)
|
||||
}
|
||||
|
|
@ -452,7 +459,7 @@ impl DataValue {
|
|||
.map_err(|_| CodecError::InvalidEncoding)?;
|
||||
|
||||
for (key, value) in entries {
|
||||
Self::write_container_entry(&mut out, key.clone(), value)?;
|
||||
Self::write_container_entry(&mut out, *key, value)?;
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
|
|
@ -520,14 +527,11 @@ impl DataValue {
|
|||
match value {
|
||||
DataValue::BoolTrue => Ok(()),
|
||||
DataValue::BoolFalse => Ok(()),
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
DataValue::Bool(v) => {
|
||||
// Kept intentionally: the kind marker already encodes the boolean,
|
||||
// so both arms carry no payload. Retained for clear compatibility.
|
||||
if *v {
|
||||
Ok(())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
if *v { Ok(()) } else { Ok(()) }
|
||||
}
|
||||
DataValue::SignedNumber(n) => {
|
||||
buf.write_i128::<BigEndian>(*n)
|
||||
|
|
@ -607,7 +611,11 @@ impl DataValue {
|
|||
|
||||
fn try_read_container(cursor: &mut Cursor<&[u8]>) -> Option<Self> {
|
||||
let count = cursor.read_u16::<BigEndian>().ok()? as usize;
|
||||
let mut entries = Vec::with_capacity(count);
|
||||
let remaining = cursor
|
||||
.get_ref()
|
||||
.len()
|
||||
.saturating_sub(cursor.position() as usize);
|
||||
let mut entries = Vec::with_capacity(count.min(remaining / Self::MIN_ENTRY_BYTES));
|
||||
|
||||
for _ in 0..count {
|
||||
let kind = cursor.read_u8().ok()?;
|
||||
|
|
@ -653,7 +661,11 @@ impl DataValue {
|
|||
|
||||
fn read_array(cursor: &mut Cursor<&[u8]>) -> Option<Self> {
|
||||
let count = cursor.read_u16::<BigEndian>().ok()? as usize;
|
||||
let mut out = Vec::with_capacity(count);
|
||||
let remaining = cursor
|
||||
.get_ref()
|
||||
.len()
|
||||
.saturating_sub(cursor.position() as usize);
|
||||
let mut out = Vec::with_capacity(count.min(remaining / Self::MIN_ENTRY_BYTES));
|
||||
|
||||
for _ in 0..count {
|
||||
let kind = cursor.read_u8().ok()?;
|
||||
|
|
@ -1185,6 +1197,22 @@ mod tests {
|
|||
assert!(DataValue::from_bytes(&bytes[..0]).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_oversized_count_does_not_overallocate() {
|
||||
// A frame declaring 65535 entries but carrying almost no payload must be
|
||||
// rejected without pre-reserving a Vec for 65535 entries. The capacity is
|
||||
// capped against remaining bytes, so these decode attempts allocate at
|
||||
// most a handful of slots before failing.
|
||||
// Container path: count = 0xFFFF, no entries follow.
|
||||
assert!(DataValue::from_bytes(&[0xFF, 0xFF]).is_none());
|
||||
// Container path with one stray byte after the count.
|
||||
assert!(DataValue::from_bytes(&[0xFF, 0xFF, 0x01]).is_none());
|
||||
// Array path: force the container parse to fail first, then the array
|
||||
// parse also sees the oversized count. A leading kind byte that is not a
|
||||
// valid container entry makes try_read_container bail to the array path.
|
||||
assert!(DataValue::from_bytes(&[0xFF, 0xFF, 0x08, 0xFF, 0xFF]).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_display_basic() {
|
||||
assert_eq!(format!("{}", DataValue::BoolTrue), "true");
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ pub use data_value::{DataKind, DataValue};
|
|||
pub use mtp_common::CodecError;
|
||||
|
||||
pub use mtp_type_map::{
|
||||
communication_type_name, data_type_name, CommunicationType, CommunicationTypeId, DataType,
|
||||
DataTypeId, TypeMap, Version, PROTOCOL_VERSION,
|
||||
CommunicationType, CommunicationTypeId, DataType, DataTypeId, PROTOCOL_VERSION, TypeMap,
|
||||
Version, communication_type_name, data_type_name,
|
||||
};
|
||||
|
||||
pub(crate) fn rand_u32() -> u32 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue