mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-19 08:08:45 +02:00
Slate: length-check ed25519/uuid fields in the JSON serde path
The serde deserialize helpers copied fixed-length byte arrays (b.copy_from_slice(&bytes[0..N])) without checking the decoded length, so a slatepack with a short pubkey/signature/uuid field panicked the wallet during deserialization. The binary path was hardened in 25dab9f; do the same for the JSON modules: reject any field whose decoded length is not exactly N. Adds a regression test that exercised the panic.
This commit is contained in:
@@ -207,6 +207,9 @@ pub mod dalek_xpubkey_serde {
|
|||||||
String::deserialize(deserializer)
|
String::deserialize(deserializer)
|
||||||
.and_then(|string| from_hex(&string).map_err(|err| Error::custom(err.to_string())))
|
.and_then(|string| from_hex(&string).map_err(|err| Error::custom(err.to_string())))
|
||||||
.and_then(|bytes: Vec<u8>| {
|
.and_then(|bytes: Vec<u8>| {
|
||||||
|
if bytes.len() != 32 {
|
||||||
|
return Err(Error::custom("unexpected byte length"));
|
||||||
|
}
|
||||||
let mut b = [0u8; 32];
|
let mut b = [0u8; 32];
|
||||||
b.copy_from_slice(&bytes[0..32]);
|
b.copy_from_slice(&bytes[0..32]);
|
||||||
Ok(xDalekPublicKey::from(b))
|
Ok(xDalekPublicKey::from(b))
|
||||||
@@ -271,6 +274,9 @@ pub mod option_dalek_pubkey_base64 {
|
|||||||
Some(string) => base64::decode(&string)
|
Some(string) => base64::decode(&string)
|
||||||
.map_err(|err| Error::custom(err.to_string()))
|
.map_err(|err| Error::custom(err.to_string()))
|
||||||
.and_then(|bytes: Vec<u8>| {
|
.and_then(|bytes: Vec<u8>| {
|
||||||
|
if bytes.len() != 32 {
|
||||||
|
return Err(Error::custom("unexpected byte length"));
|
||||||
|
}
|
||||||
let mut b = [0u8; 32];
|
let mut b = [0u8; 32];
|
||||||
b.copy_from_slice(&bytes[0..32]);
|
b.copy_from_slice(&bytes[0..32]);
|
||||||
DalekPublicKey::from_bytes(&b)
|
DalekPublicKey::from_bytes(&b)
|
||||||
@@ -313,6 +319,9 @@ pub mod option_dalek_pubkey_serde {
|
|||||||
Some(string) => from_hex(&string)
|
Some(string) => from_hex(&string)
|
||||||
.map_err(|err| Error::custom(err.to_string()))
|
.map_err(|err| Error::custom(err.to_string()))
|
||||||
.and_then(|bytes: Vec<u8>| {
|
.and_then(|bytes: Vec<u8>| {
|
||||||
|
if bytes.len() != 32 {
|
||||||
|
return Err(Error::custom("unexpected byte length"));
|
||||||
|
}
|
||||||
let mut b = [0u8; 32];
|
let mut b = [0u8; 32];
|
||||||
b.copy_from_slice(&bytes[0..32]);
|
b.copy_from_slice(&bytes[0..32]);
|
||||||
DalekPublicKey::from_bytes(&b)
|
DalekPublicKey::from_bytes(&b)
|
||||||
@@ -352,6 +361,9 @@ pub mod option_xdalek_pubkey_serde {
|
|||||||
Some(string) => from_hex(&string)
|
Some(string) => from_hex(&string)
|
||||||
.map_err(|err| Error::custom(err.to_string()))
|
.map_err(|err| Error::custom(err.to_string()))
|
||||||
.and_then(|bytes: Vec<u8>| {
|
.and_then(|bytes: Vec<u8>| {
|
||||||
|
if bytes.len() != 32 {
|
||||||
|
return Err(Error::custom("unexpected byte length"));
|
||||||
|
}
|
||||||
let mut b = [0u8; 32];
|
let mut b = [0u8; 32];
|
||||||
b.copy_from_slice(&bytes[0..32]);
|
b.copy_from_slice(&bytes[0..32]);
|
||||||
Ok(Some(xDalekPublicKey::from(b)))
|
Ok(Some(xDalekPublicKey::from(b)))
|
||||||
@@ -386,6 +398,9 @@ pub mod dalek_sig_serde {
|
|||||||
String::deserialize(deserializer)
|
String::deserialize(deserializer)
|
||||||
.and_then(|string| from_hex(&string).map_err(|err| Error::custom(err.to_string())))
|
.and_then(|string| from_hex(&string).map_err(|err| Error::custom(err.to_string())))
|
||||||
.and_then(|bytes: Vec<u8>| {
|
.and_then(|bytes: Vec<u8>| {
|
||||||
|
if bytes.len() != 64 {
|
||||||
|
return Err(Error::custom("unexpected byte length"));
|
||||||
|
}
|
||||||
let mut b = [0u8; 64];
|
let mut b = [0u8; 64];
|
||||||
b.copy_from_slice(&bytes[0..64]);
|
b.copy_from_slice(&bytes[0..64]);
|
||||||
DalekSignature::try_from(b).map_err(|err| Error::custom(err.to_string()))
|
DalekSignature::try_from(b).map_err(|err| Error::custom(err.to_string()))
|
||||||
@@ -422,6 +437,9 @@ pub mod option_dalek_sig_serde {
|
|||||||
Some(string) => from_hex(&string)
|
Some(string) => from_hex(&string)
|
||||||
.map_err(|err| Error::custom(err.to_string()))
|
.map_err(|err| Error::custom(err.to_string()))
|
||||||
.and_then(|bytes: Vec<u8>| {
|
.and_then(|bytes: Vec<u8>| {
|
||||||
|
if bytes.len() != 64 {
|
||||||
|
return Err(Error::custom("unexpected byte length"));
|
||||||
|
}
|
||||||
let mut b = [0u8; 64];
|
let mut b = [0u8; 64];
|
||||||
b.copy_from_slice(&bytes[0..64]);
|
b.copy_from_slice(&bytes[0..64]);
|
||||||
DalekSignature::try_from(b)
|
DalekSignature::try_from(b)
|
||||||
@@ -461,6 +479,9 @@ pub mod option_dalek_sig_base64 {
|
|||||||
Some(string) => base64::decode(&string)
|
Some(string) => base64::decode(&string)
|
||||||
.map_err(|err| Error::custom(err.to_string()))
|
.map_err(|err| Error::custom(err.to_string()))
|
||||||
.and_then(|bytes: Vec<u8>| {
|
.and_then(|bytes: Vec<u8>| {
|
||||||
|
if bytes.len() != 64 {
|
||||||
|
return Err(Error::custom("unexpected byte length"));
|
||||||
|
}
|
||||||
let mut b = [0u8; 64];
|
let mut b = [0u8; 64];
|
||||||
b.copy_from_slice(&bytes[0..64]);
|
b.copy_from_slice(&bytes[0..64]);
|
||||||
DalekSignature::try_from(b)
|
DalekSignature::try_from(b)
|
||||||
@@ -671,6 +692,9 @@ pub mod uuid_base64 {
|
|||||||
base64::decode(&string).map_err(|err| Error::custom(err.to_string()))
|
base64::decode(&string).map_err(|err| Error::custom(err.to_string()))
|
||||||
})
|
})
|
||||||
.and_then(|bytes: Vec<u8>| {
|
.and_then(|bytes: Vec<u8>| {
|
||||||
|
if bytes.len() != 16 {
|
||||||
|
return Err(Error::custom("unexpected byte length"));
|
||||||
|
}
|
||||||
let mut b = [0u8; 16];
|
let mut b = [0u8; 16];
|
||||||
b.copy_from_slice(&bytes[0..16]);
|
b.copy_from_slice(&bytes[0..16]);
|
||||||
Ok(Uuid::from_bytes(b))
|
Ok(Uuid::from_bytes(b))
|
||||||
@@ -744,4 +768,22 @@ mod test {
|
|||||||
assert_eq!(s, deserialized);
|
assert_eq!(s, deserialized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_malformed_dalek_fields() {
|
||||||
|
// A too-short fixed-length field used to panic inside copy_from_slice during
|
||||||
|
// deserialization; it must now surface as an error instead.
|
||||||
|
let json = serde_json::to_string(&SerTest::random()).unwrap();
|
||||||
|
let value: serde_json::Value = serde_json::from_str(&json).unwrap();
|
||||||
|
|
||||||
|
// Signature field shorter than 64 bytes (exercises the dalek_sig_serde guard).
|
||||||
|
let mut bad = value.clone();
|
||||||
|
bad["sig"] = serde_json::Value::String("00".to_string());
|
||||||
|
assert!(serde_json::from_value::<SerTest>(bad).is_err());
|
||||||
|
|
||||||
|
// Public-key field shorter than 32 bytes.
|
||||||
|
let mut bad = value;
|
||||||
|
bad["pub_key"] = serde_json::Value::String("00".to_string());
|
||||||
|
assert!(serde_json::from_value::<SerTest>(bad).is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user