Merge pull request #706 from Foundation-Devices/SFT-8178-core-urtypes-migration
What changed, and why it matters
This commit updates a Rust library dependency (foundation-urtypes) used in the Passport hardware wallet firmware to a newer version that includes 'arena fixes.' The code changes rename some data types to use borrowed references (e.g., HDKeyRef instead of HDKey) and add a test to verify that optional key metadata round-trips correctly. The commit message and diff do not describe a specific security vulnerability, exploit, or attack scenario. It appears to be a routine maintenance/migration change that may incidentally improve memory safety, but there is no direct evidence that it fixes an actively exploitable security flaw.
Review the upstream foundation-urtypes and foundation-arena changelogs or release notes to determine whether the 'arena fixes' address a security-relevant memory-safety issue. If the upstream update fixes a vulnerability, assess whether Passport firmware versions before this commit are affected and consider issuing a security advisory. Otherwise, treat as routine maintenance and continue normal regression testing.
Security signals we found
Dependency update to foundation-urtypes 0.5.1 and foundation-arena 0.1.1
Commit title mentions 'arena fixes'
Type migration from owned/borrowed types to explicit reference types (Ref suffix)
Addition of round-trip test for optional HDKey metadata
No explicit vulnerability description, CVE, or exploit details in commit or references
Evidence from the diff
The commit bumps foundation-urtypes from 0.4.1 to 0.5.1 and foundation-arena from 0.1.0 to 0.1.1, swaps the hex crate for faster-hex, and updates the Rust bridge in extmod/foundation-rust/src/ur/registry.rs to use new reference-based types (DerivedKeyRef, HDKeyRef, KeypathRef). A new unit test, borrowed_hdkey_bridge_roundtrips_optional_metadata, checks that optional chain_code, use_info, origin, and parent_fingerprint fields are preserved through CBOR encode/decode. The phrase ‘arena fixes’ in the commit title suggests the upstream library update may correct memory-arena behavior, but no CVE, advisory, or detailed changelog is provided in the commit or references.
Changed components
extmod/foundation-rust/Cargo.lockextmod/foundation-rust/Cargo.tomlextmod/foundation-rust/src/ur/registry.rsfoundation-urtypes Rust crate (dependency)foundation-arena Rust crate (dependency)Inspect captured patch +80 / −26
### extmod/foundation-rust/Cargo.lock
@@ -100,6 +100,12 @@ dependencies = [
"void",
]
+[[package]]
+name = "faster-hex"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183"
+
[[package]]
name = "foundation"
version = "0.1.0"
@@ -121,9 +127,9 @@ dependencies = [
[[package]]
name = "foundation-arena"
-version = "0.1.0"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e6bdea1eeaa5edb5355234d02f81c6dbdd4bc5146887990dd29a213029bbeae"
+checksum = "777e495443499419b935d80c5abffb7e7006859242c8a1d40b5831fea4911175"
[[package]]
name = "foundation-firmware"
@@ -154,13 +160,13 @@ dependencies = [
[[package]]
name = "foundation-urtypes"
-version = "0.4.1"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e40662e96946962894b2ff376b848af3e8beb2939be091358dfe2df9db8eaa55"
+checksum = "9c1d89bc1e19e34ae9c303d957c486bf17b956788fcb1c2ca5c413dbed90bea8"
dependencies = [
+ "faster-hex",
"foundation-arena",
"heapless",
- "hex",
"minicbor",
"uuid",
]
@@ -195,12 +201,6 @@ dependencies = [
"stable_deref_trait",
]
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
[[package]]
name = "hex-conservative"
version = "0.3.0"
### extmod/foundation-rust/Cargo.toml
@@ -37,7 +37,7 @@ version = "0.4"
default-features = false
[dependencies.foundation-urtypes]
-version = "0.4.1"
+version = "0.5.1"
default-features = false
[target.'cfg(target_arch = "arm")'.dependencies.cortex-m]
### extmod/foundation-rust/src/ur/registry.rs
@@ -7,8 +7,8 @@ use foundation_urtypes::{
passport::Model,
registry::PassportRequest,
registry::{
- CoinInfo, CoinType, DerivedKey, HDKey, Keypath, PassportResponse,
- PathComponents,
+ CoinInfo, CoinType, DerivedKeyRef, HDKeyRef, KeypathRef,
+ PassportResponse, PathComponents,
},
supply_chain_validation::{Challenge, Solution},
value,
@@ -203,10 +203,12 @@ pub enum UR_HDKey {
DerivedKey(UR_DerivedKey),
}
-impl<'a> From<&'a UR_HDKey> for HDKey<'a> {
- fn from(value: &'a UR_HDKey) -> HDKey<'a> {
+impl<'a> From<&'a UR_HDKey> for HDKeyRef<'a> {
+ fn from(value: &'a UR_HDKey) -> HDKeyRef<'a> {
match value {
- UR_HDKey::DerivedKey(v) => HDKey::DerivedKey(DerivedKey::from(v)),
+ UR_HDKey::DerivedKey(v) => {
+ HDKeyRef::DerivedKey(DerivedKeyRef::from(v))
+ }
}
}
}
@@ -237,9 +239,9 @@ pub struct UR_DerivedKey {
pub parent_fingerprint: u32,
}
-impl<'a> From<&'a UR_DerivedKey> for DerivedKey<'a> {
- fn from(value: &'a UR_DerivedKey) -> DerivedKey<'a> {
- DerivedKey {
+impl<'a> From<&'a UR_DerivedKey> for DerivedKeyRef<'a> {
+ fn from(value: &'a UR_DerivedKey) -> DerivedKeyRef<'a> {
+ DerivedKeyRef {
is_private: value.is_private,
key_data: value.key_data,
chain_code: if value.has_chain_code {
@@ -253,7 +255,7 @@ impl<'a> From<&'a UR_DerivedKey> for DerivedKey<'a> {
None
},
origin: if value.has_origin {
- Some(Keypath::from(&value.origin))
+ Some(KeypathRef::from(&value.origin))
} else {
None
},
@@ -311,8 +313,8 @@ pub struct UR_Keypath {
pub has_depth: bool,
}
-impl<'a> From<Keypath<'a>> for UR_Keypath {
- fn from(v: Keypath<'a>) -> UR_Keypath {
+impl<'a> From<KeypathRef<'a>> for UR_Keypath {
+ fn from(v: KeypathRef<'a>) -> UR_Keypath {
UR_Keypath {
source_fingerprint: v
.source_fingerprint
@@ -324,9 +326,9 @@ impl<'a> From<Keypath<'a>> for UR_Keypath {
}
}
-impl<'a> From<&'a UR_Keypath> for Keypath<'a> {
- fn from(v: &UR_Keypath) -> Keypath<'a> {
- Keypath {
+impl<'a> From<&'a UR_Keypath> for KeypathRef<'a> {
+ fn from(v: &UR_Keypath) -> KeypathRef<'a> {
+ KeypathRef {
components: PathComponents::from(&[]),
source_fingerprint: NonZeroU32::new(v.source_fingerprint),
depth: if v.has_depth { Some(v.depth) } else { None },
@@ -602,6 +604,58 @@ mod tests {
use super::*;
use minicbor::encode::write::Cursor;
+ #[test]
+ fn borrowed_hdkey_bridge_roundtrips_optional_metadata() {
+ for present in [false, true] {
+ let mut value = UR_Value::Bytes {
+ data: core::ptr::null(),
+ len: 0,
+ };
+ let key_data = [2u8; 33];
+ let chain_code = [3u8; 32];
+ let coin = UR_CoinInfo {
+ coin_type: UR_CoinType::BTC,
+ network: UR_NETWORK_TESTNET as u64,
+ };
+ let origin = UR_Keypath {
+ source_fingerprint: 0x1234_5678,
+ depth: 4,
+ has_depth: true,
+ };
+ ur_registry_new_derived_key(
+ &mut value,
+ false,
+ &key_data,
+ present.then_some(&chain_code),
+ present.then_some(&coin),
+ present.then_some(&origin),
+ if present { 0x2345_6789 } else { 0 },
+ );
+ // The constructor above initializes owned UR_HDKey storage.
+ let Value::HDKey(key) = (unsafe { value.to_value() }) else {
+ panic!("expected hdkey");
+ };
+ let mut output = Cursor::new([0u8; 256]);
+ key.encode(&mut Encoder::new(&mut output), &mut ()).unwrap();
+ let encoded = &output.get_ref()[..output.position()];
+ let decoded: HDKeyRef<'_> = minicbor::decode(encoded).unwrap();
+ assert_eq!(decoded, key);
+ let HDKeyRef::DerivedKey(derived) = decoded else {
+ panic!("expected derived key");
+ };
+ assert_eq!(derived.key_data, key_data);
+ assert!(!derived.is_private);
+ assert_eq!(derived.chain_code, present.then_some(chain_code));
+ assert_eq!(derived.use_info.is_some(), present);
+ assert_eq!(derived.origin.is_some(), present);
+ assert_eq!(derived.parent_fingerprint.is_some(), present);
+ if let Some(path) = derived.origin {
+ assert_eq!(path.source_fingerprint.unwrap().get(), 0x1234_5678);
+ assert_eq!(path.depth, Some(4));
+ }
+ }
+ }
+
#[test]
fn casa_crypto_account_wire_format_is_pinned() {
let account = UR_CryptoAccount {Why this scored 24/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.