Skip to content

Commit

Permalink
[host] Add owner blob support for ISFB TLV entry.
Browse files Browse the repository at this point in the history
This change adds support for the Integration Specific Firmware Binding
(ISFB) configuration, which describes the configuration parameters of
the ISFB region.

This owner blob TLV entry is optional and not required for regular
ownership operation.

Signed-off-by: Miguel Osorio <[email protected]>
  • Loading branch information
moidx committed Oct 25, 2024
1 parent 6677e8f commit 27c0914
Show file tree
Hide file tree
Showing 5 changed files with 189 additions and 4 deletions.
1 change: 1 addition & 0 deletions sw/host/opentitanlib/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ rust_library(
"src/ownership/application_key.rs",
"src/ownership/flash.rs",
"src/ownership/flash_info.rs",
"src/ownership/isfb.rs",
"src/ownership/misc.rs",
"src/ownership/mod.rs",
"src/ownership/owner.rs",
Expand Down
155 changes: 155 additions & 0 deletions sw/host/opentitanlib/src/ownership/isfb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use serde::{Deserialize, Serialize};
use serde_annotate::Annotate;
use std::io::{Read, Write};

use super::application_key::ApplicationKeyDomain;
use super::misc::{TlvHeader, TlvTag};
use super::GlobalFlags;

/// The owner Integration Specific Firmware Binding (ISFB) configuration
/// describes the configuration parameters for the ISFB region.
#[derive(Debug, Serialize, Deserialize, Annotate)]
pub struct OwnerIsfbConfig {
/// Header identifying this struct.
#[serde(
skip_serializing_if = "GlobalFlags::not_debug",
default = "OwnerIsfbConfig::default_header"
)]
pub header: TlvHeader,
/// The flash bank where the ISFB is located.
pub bank: u8,
/// The info flash page where the ISFB is located.
pub page: u8,
/// Padding for alignment.
#[serde(default, skip_serializing_if = "GlobalFlags::not_debug")]
#[annotate(format=hex)]
pub pad: u16,

/// The erase policy for the ISFB region.
#[annotate(format=hex)]
pub erase_conditions: u32,
/// The key domain associated with the erase condition policy.
#[annotate(format=hex)]
pub key_domain: ApplicationKeyDomain,
/// Reserved for future use.
#[serde(default, skip_serializing_if = "GlobalFlags::not_debug")]
#[annotate(format=hex)]
pub reserved: [u32; 5],
/// Number of `uint32_t` reserved for product expressions. It has to be a
/// value less than or equal to 256.
pub product_words: u32,
}

impl Default for OwnerIsfbConfig {
fn default() -> Self {
Self {
header: Self::default_header(),
bank: 0u8,
page: 0u8,
pad: 0u16,
erase_conditions: 0u32,
key_domain: ApplicationKeyDomain::default(),
reserved: [0u32; 5],
product_words: 0u32,
}
}
}

impl OwnerIsfbConfig {
const SIZE: usize = 2048;
pub fn default_header() -> TlvHeader {
TlvHeader::new(TlvTag::IntegratorSpecificFirmwareBinding, Self::SIZE, "0.0")
}
pub fn read(src: &mut impl Read, header: TlvHeader) -> Result<Self> {
let bank = src.read_u8()?;
let page = src.read_u8()?;
let pad = src.read_u16::<LittleEndian>()?;
let erase_conditions = src.read_u32::<LittleEndian>()?;
let key_domain = ApplicationKeyDomain(src.read_u32::<LittleEndian>()?);
let mut reserved = [0u32; 5];
src.read_u32_into::<LittleEndian>(&mut reserved)?;
let product_words = src.read_u32::<LittleEndian>()?;
Ok(Self {
header,
bank,
page,
pad,
erase_conditions,
key_domain,
reserved,
product_words,
})
}
pub fn write(&self, dest: &mut impl Write) -> Result<()> {
let header = Self::default_header();
header.write(dest)?;

dest.write_u8(self.bank)?;
dest.write_u8(self.page)?;
dest.write_u16::<LittleEndian>(self.pad)?;
dest.write_u32::<LittleEndian>(self.erase_conditions)?;
dest.write_u32::<LittleEndian>(u32::from(self.key_domain))?;
for x in &self.reserved {
dest.write_u32::<LittleEndian>(*x)?;
}
dest.write_u32::<LittleEndian>(self.product_words)?;
Ok(())
}
}

#[cfg(test)]
mod test {
use super::*;
use crate::util::hexdump::{hexdump_parse, hexdump_string};

const OWNER_ISFB_CONF: &str = "\
00000000: 49 53 46 42 00 08 00 00 01 08 00 00 66 06 00 00 ISFB........f...
00000010: 70 72 6f 64 00 00 00 00 00 00 00 00 00 00 00 00 prod............
00000020: 00 00 00 00 00 00 00 00 80 00 00 00 ............
";
const OWNER_ISFB_CONF_JSON: &str = r#"{
bank: 1,
page: 8,
erase_conditions: 0x666,
key_domain: "Prod",
product_words: 128
}"#;

#[test]
fn test_owner_isfb_config_write() -> Result<()> {
let isfb = OwnerIsfbConfig {
header: TlvHeader::default(),
bank: 1,
page: 8,
pad: 0,
erase_conditions: 0x0000_0666,
key_domain: ApplicationKeyDomain::Prod,
product_words: 128,
..Default::default()
};

let mut bin = Vec::new();
isfb.write(&mut bin)?;
eprintln!("{}", hexdump_string(&bin)?);
assert_eq!(hexdump_string(&bin)?, OWNER_ISFB_CONF);
Ok(())
}

#[test]
fn test_owner_isfb_config_read() -> Result<()> {
let buf = hexdump_parse(OWNER_ISFB_CONF)?;
let mut cur = std::io::Cursor::new(&buf);
let header = TlvHeader::read(&mut cur)?;
let orc = OwnerIsfbConfig::read(&mut cur, header)?;
let doc = serde_annotate::serialize(&orc)?.to_json5().to_string();
eprintln!("{}", doc);
assert_eq!(doc, OWNER_ISFB_CONF_JSON);
Ok(())
}
}
1 change: 1 addition & 0 deletions sw/host/opentitanlib/src/ownership/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ with_unknown! {
FlashConfig = u32::from_le_bytes(*b"FLSH"),
FlashInfoConfig = u32::from_le_bytes(*b"INFO"),
Rescue = u32::from_le_bytes(*b"RESQ"),
IntegratorSpecificFirmwareBinding = u32::from_le_bytes(*b"ISFB"),
NotPresent = u32::from_le_bytes(*b"ZZZZ"),
}

Expand Down
2 changes: 2 additions & 0 deletions sw/host/opentitanlib/src/ownership/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ use std::sync::atomic::{AtomicBool, Ordering};
mod application_key;
mod flash;
mod flash_info;
mod isfb;
mod misc;
pub mod owner;
mod rescue;

pub use application_key::{ApplicationKeyDomain, OwnerApplicationKey};
pub use flash::{FlashFlags, OwnerFlashConfig, OwnerFlashRegion};
pub use flash_info::{OwnerFlashInfoConfig, OwnerInfoPage};
pub use isfb::OwnerIsfbConfig;
pub use misc::{KeyMaterial, OwnershipKeyAlg, TlvHeader, TlvTag};
pub use owner::{OwnerBlock, OwnerConfigItem, SramExecMode};
pub use rescue::{CommandTag, OwnerRescueConfig, RescueType};
Expand Down
34 changes: 30 additions & 4 deletions sw/host/opentitanlib/src/ownership/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use std::io::{Read, Write};

use super::misc::{KeyMaterial, OwnershipKeyAlg, TlvHeader, TlvTag};
use super::GlobalFlags;
use super::{OwnerApplicationKey, OwnerFlashConfig, OwnerFlashInfoConfig, OwnerRescueConfig};
use super::{
OwnerApplicationKey, OwnerFlashConfig, OwnerFlashInfoConfig, OwnerIsfbConfig, OwnerRescueConfig,
};
use crate::crypto::ecdsa::{EcdsaPrivateKey, EcdsaRawSignature};
use crate::with_unknown;

Expand Down Expand Up @@ -244,6 +246,8 @@ pub enum OwnerConfigItem {
FlashConfig(OwnerFlashConfig),
#[serde(alias = "rescue_config")]
RescueConfig(OwnerRescueConfig),
#[serde(alias = "isfb_config")]
IsfbConfig(OwnerIsfbConfig),
#[serde(alias = "raw")]
Raw(
#[serde(with = "serde_bytes")]
Expand All @@ -259,6 +263,7 @@ impl OwnerConfigItem {
Self::FlashInfoConfig(x) => x.write(dest)?,
Self::FlashConfig(x) => x.write(dest)?,
Self::RescueConfig(x) => x.write(dest)?,
Self::IsfbConfig(x) => x.write(dest)?,
Self::Raw(x) => dest.write_all(x)?,
}
Ok(())
Expand All @@ -273,6 +278,9 @@ impl OwnerConfigItem {
Self::FlashInfoConfig(OwnerFlashInfoConfig::read(src, header)?)
}
TlvTag::Rescue => Self::RescueConfig(OwnerRescueConfig::read(src, header)?),
TlvTag::IntegratorSpecificFirmwareBinding => {
Self::IsfbConfig(OwnerIsfbConfig::read(src, header)?)
}
TlvTag::NotPresent => return Ok(None),
_ => {
let mut data = Vec::new();
Expand Down Expand Up @@ -345,9 +353,9 @@ r#"00000000: 4f 57 4e 52 00 08 00 00 00 00 00 00 4c 4e 45 58 OWNR........LNEX
00000270: 41 43 54 56 51 53 45 52 42 53 45 52 4f 42 45 52 ACTVQSERBSEROBER
00000280: 47 4f 4c 42 51 45 52 42 50 53 52 42 52 4e 57 4f GOLBQERBPSRBRNWO
00000290: 30 47 50 4f 31 47 50 4f 44 49 54 4f 54 49 41 57 0GPO1GPODITOTIAW
000002a0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
000002b0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
000002c0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
000002a0: 49 53 46 42 00 08 00 00 01 08 00 00 66 06 00 00 ISFB........f...
000002b0: 70 72 6f 64 00 00 00 00 00 00 00 00 00 00 00 00 prod............
000002c0: 00 00 00 00 00 00 00 00 80 00 00 00 5a 5a 5a 5a ............ZZZZ
000002d0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
000002e0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
000002f0: 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a 5a ZZZZZZZZZZZZZZZZ
Expand Down Expand Up @@ -567,6 +575,15 @@ r#"00000000: 4f 57 4e 52 00 08 00 00 00 00 00 00 4c 4e 45 58 OWNR........LNEX
"Wait"
]
}
},
{
IsfbConfig: {
bank: 1,
page: 8,
erase_conditions: 0x666,
key_domain: "Prod",
product_words: 128
}
}
],
signature: {
Expand Down Expand Up @@ -631,6 +648,15 @@ r#"00000000: 4f 57 4e 52 00 08 00 00 00 00 00 00 4c 4e 45 58 OWNR........LNEX
..Default::default()
}),
OwnerConfigItem::RescueConfig(OwnerRescueConfig::all()),
OwnerConfigItem::IsfbConfig(OwnerIsfbConfig {
bank: 1,
page: 8,
pad: 0,
erase_conditions: 0x0000_0666,
key_domain: ApplicationKeyDomain::Prod,
product_words: 128,
..Default::default()
}),
],
signature: EcdsaRawSignature {
r: hex::decode("7777777777777777777777777777777777777777777777777777777777777777")?,
Expand Down

0 comments on commit 27c0914

Please sign in to comment.