sim: Add hw-rollback-protection feature
This commit adds simulator support to test the
hw-rollback-protection feature which is using
nv-counters. In the simulator they are stored in Rust
to prevent any race conditions from happening due to
the parallel execution of the tests.
Signed-off-by: Roland Mikhel <roland.mikhel@arm.com>
Change-Id: I445fc50615ed1f0c06e5933b16811c24d9d302fc
diff --git a/sim/src/caps.rs b/sim/src/caps.rs
index e7240d1..912dda1 100644
--- a/sim/src/caps.rs
+++ b/sim/src/caps.rs
@@ -27,6 +27,7 @@
Aes256 = (1 << 14),
RamLoad = (1 << 15),
DirectXip = (1 << 16),
+ HwRollbackProtection = (1 << 17),
}
impl Caps {
diff --git a/sim/src/image.rs b/sim/src/image.rs
index 424f646..9b46ca0 100644
--- a/sim/src/image.rs
+++ b/sim/src/image.rs
@@ -221,11 +221,11 @@
Box::new(BoringDep::new(image_num, deps))
};
let primaries = install_image(&mut flash, &slots[0],
- maximal(42784), &ram, &*dep, false);
+ maximal(42784), &ram, &*dep, false, Some(0));
let upgrades = match deps.depends[image_num] {
DepType::NoUpgrade => install_no_image(),
_ => install_image(&mut flash, &slots[1],
- maximal(46928), &ram, &*dep, false)
+ maximal(46928), &ram, &*dep, false, Some(0))
};
OneImage {
slots,
@@ -274,9 +274,9 @@
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
let dep = BoringDep::new(image_num, &NO_DEPS);
let primaries = install_image(&mut bad_flash, &slots[0],
- maximal(32784), &ram, &dep, false);
+ maximal(32784), &ram, &dep, false, Some(0));
let upgrades = install_image(&mut bad_flash, &slots[1],
- maximal(41928), &ram, &dep, true);
+ maximal(41928), &ram, &dep, true, Some(0));
OneImage {
slots,
primaries,
@@ -297,9 +297,9 @@
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
let dep = BoringDep::new(image_num, &NO_DEPS);
let primaries = install_image(&mut bad_flash, &slots[0],
- maximal(32784), &ram, &dep, false);
+ maximal(32784), &ram, &dep, false, Some(0));
let upgrades = install_image(&mut bad_flash, &slots[1],
- ImageSize::Oversized, &ram, &dep, false);
+ ImageSize::Oversized, &ram, &dep, false, Some(0));
OneImage {
slots,
primaries,
@@ -320,7 +320,7 @@
let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
let dep = BoringDep::new(image_num, &NO_DEPS);
let primaries = install_image(&mut flash, &slots[0],
- maximal(32784), &ram, &dep, false);
+ maximal(32784), &ram, &dep, false, Some(0));
let upgrades = install_no_image();
OneImage {
slots,
@@ -343,7 +343,7 @@
let dep = BoringDep::new(image_num, &NO_DEPS);
let primaries = install_no_image();
let upgrades = install_image(&mut flash, &slots[1],
- maximal(32784), &ram, &dep, false);
+ maximal(32784), &ram, &dep, false, Some(0));
OneImage {
slots,
primaries,
@@ -365,7 +365,31 @@
let dep = BoringDep::new(image_num, &NO_DEPS);
let primaries = install_no_image();
let upgrades = install_image(&mut flash, &slots[1],
- ImageSize::Oversized, &ram, &dep, false);
+ ImageSize::Oversized, &ram, &dep, false, Some(0));
+ OneImage {
+ slots,
+ primaries,
+ upgrades,
+ }}).collect();
+ Images {
+ flash,
+ areadesc: self.areadesc,
+ images,
+ total_count: None,
+ ram: self.ram,
+ }
+ }
+
+ /// If security_cnt is None then do not add a security counter TLV, otherwise add the specified value.
+ pub fn make_image_with_security_counter(self, security_cnt: Option<u32>) -> Images {
+ let mut flash = self.flash;
+ let ram = self.ram.clone(); // TODO: Avoid this clone.
+ let images = self.slots.into_iter().enumerate().map(|(image_num, slots)| {
+ let dep = BoringDep::new(image_num, &NO_DEPS);
+ let primaries = install_image(&mut flash, &slots[0],
+ maximal(32784), &ram, &dep, false, security_cnt);
+ let upgrades = install_image(&mut flash, &slots[1],
+ maximal(41928), &ram, &dep, false, security_cnt.map(|v| v + 1));
OneImage {
slots,
primaries,
@@ -1269,6 +1293,31 @@
return false;
}
+ pub fn run_hw_rollback_prot(&self) -> bool {
+ if !Caps::HwRollbackProtection.present() {
+ return false;
+ }
+
+ let mut flash = self.flash.clone();
+
+ // set the "stored" security counter to a fixed value.
+ c::set_security_counter(0, 30);
+
+ let result = c::boot_go(&mut flash, &self.areadesc, None, None, true);
+
+ if result.success() {
+ warn!("Successful boot when it did not suppose to happen!");
+ return true;
+ }
+ let counter_val = c::get_security_counter(0);
+ if counter_val != 30 {
+ warn!("Counter was changed when it did not suppose to!");
+ return true;
+ }
+
+ false
+ }
+
/// Adds a new flash area that fails statistically
fn mark_bad_status_with_rate(&self, flash: &mut SimMultiFlash, slot: usize,
rate: f32) {
@@ -1650,7 +1699,7 @@
/// fields used by the given code. Returns a copy of the image that was written.
fn install_image(flash: &mut SimMultiFlash, slot: &SlotInfo, len: ImageSize,
ram: &RamData,
- deps: &dyn Depender, bad_sig: bool) -> ImageData {
+ deps: &dyn Depender, bad_sig: bool, security_counter:Option<u32>) -> ImageData {
let offset = slot.base_off;
let slot_len = slot.len;
let dev_id = slot.dev_id;
@@ -1658,6 +1707,8 @@
let mut tlv: Box<dyn ManifestGen> = Box::new(make_tlv());
+ tlv.set_security_counter(security_counter);
+
// Add the dependencies early to the tlv.
for dep in deps.my_deps(offset, slot.index) {
tlv.add_dependency(deps.other_id(), &dep);
@@ -1891,6 +1942,8 @@
TlvGen::new_ecdsa()
} else if Caps::Ed25519.present() {
TlvGen::new_ed25519()
+ } else if Caps::HwRollbackProtection.present() {
+ TlvGen::new_sec_cnt()
} else {
TlvGen::new_hash_only()
}
diff --git a/sim/src/tlv.rs b/sim/src/tlv.rs
index c924043..99c02d9 100644
--- a/sim/src/tlv.rs
+++ b/sim/src/tlv.rs
@@ -59,6 +59,7 @@
ENCEC256 = 0x32,
ENCX25519 = 0x33,
DEPENDENCY = 0x40,
+ SECCNT = 0x50,
}
#[allow(dead_code, non_camel_case_types)]
@@ -108,6 +109,9 @@
/// Return the current encryption key
fn get_enc_key(&self) -> Vec<u8>;
+
+ /// Set the security counter to the specified value.
+ fn set_security_counter(&mut self, security_cnt: Option<u32>);
}
#[derive(Debug, Default)]
@@ -119,6 +123,7 @@
enc_key: Vec<u8>,
/// Should this signature be corrupted.
gen_corrupted: bool,
+ security_cnt: Option<u32>,
}
#[derive(Debug)]
@@ -294,6 +299,15 @@
..Default::default()
}
}
+
+ #[allow(dead_code)]
+ pub fn new_sec_cnt() -> TlvGen {
+ TlvGen {
+ kinds: vec![TlvKinds::SHA256, TlvKinds::SECCNT],
+ ..Default::default()
+ }
+ }
+
}
impl ManifestGen for TlvGen {
@@ -317,12 +331,17 @@
}
fn protect_size(&self) -> u16 {
- if self.dependencies.is_empty() {
- 0
- } else {
- // Include the header and space for each dependency.
- 4 + (self.dependencies.len() as u16) * (4 + 4 + 8)
+ let mut size = 0;
+ if !self.dependencies.is_empty() || (Caps::HwRollbackProtection.present() && self.security_cnt.is_some()) {
+ // include the TLV area header.
+ size += 4;
+ // add space for each dependency.
+ size += (self.dependencies.len() as u16) * (4 + std::mem::size_of::<Dependency>() as u16);
+ if Caps::HwRollbackProtection.present() && self.security_cnt.is_some() {
+ size += 4 + 4;
+ }
}
+ size
}
fn add_dependency(&mut self, id: u8, version: &ImageVersion) {
@@ -385,10 +404,8 @@
estimate += 4 + if aes256 { 96 } else { 80 };
}
- // Gather the size of the dependency information.
- if self.protect_size() > 0 {
- estimate += 4 + (16 * self.dependencies.len());
- }
+ // Gather the size of the protected TLV area.
+ estimate += self.protect_size() as usize;
estimate
}
@@ -418,6 +435,13 @@
protected_tlv.write_u32::<LittleEndian>(dep.version.build_num).unwrap();
}
+ // Security counter has to be at the protected TLV area also
+ if Caps::HwRollbackProtection.present() && self.security_cnt.is_some() {
+ protected_tlv.write_u16::<LittleEndian>(TlvKinds::SECCNT as u16).unwrap();
+ protected_tlv.write_u16::<LittleEndian>(std::mem::size_of::<u32>() as u16).unwrap();
+ protected_tlv.write_u32::<LittleEndian>(self.security_cnt.unwrap() as u32).unwrap();
+ }
+
assert_eq!(size, protected_tlv.len() as u16, "protected TLV length incorrect");
}
@@ -765,6 +789,10 @@
}
self.enc_key.clone()
}
+
+ fn set_security_counter(&mut self, security_cnt: Option<u32>) {
+ self.security_cnt = security_cnt;
+ }
}
include!("rsa_pub_key-rs.txt");