use core::convert::TryInto;
use core::fmt;
use std::io::Write as _;
use crate::pki::{format_bytes, Sha256Hash};
use crate::util::{hex_deserialize_256, hex_serialize, is_default};
use serde::{Deserialize, Serialize};
use sha2::Digest as _;
use nom::{bytes::complete::take, number::complete::le_u32, IResult};
use serde_big_array::BigArray;
pub mod debug;
pub use debug::{DebugAccess, DebugSettings};
pub const FACTORY_SETTINGS_ADDRESS: usize = 0x9_E400;
pub const CUSTOMER_SETTINGS_SCRATCH_ADDRESS: usize = 0x9_DE00;
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct ProtectedFlash {
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub customer: CustomerSettingsArea,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub factory_settings: FactorySettings,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub keystore: Keystore,
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
pub struct FactorySettings<CustomerData = RawCustomerData, VendorUsage = RawVendorUsage>
where
CustomerData: FactorySettingsCustomerData,
VendorUsage: FactorySettingsVendorUsage,
{
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub boot_configuration: BootConfiguration,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub usb_id: UsbId,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub debug_access: DebugAccess,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub vendor_usage: VendorUsage,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub secure_boot_configuration: SecureBootConfiguration,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub prince_configuration: PrinceConfiguration,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub prince_subregions: [PrinceSubregion; 3],
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
#[serde(deserialize_with = "hex_deserialize_256")]
pub rot_fingerprint: Sha256Hash,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub customer_data: CustomerData,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
sha256_hash: Sha256Hash,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub seal: bool,
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "kebab-case")]
#[serde(deny_unknown_fields)]
pub struct CustomerSettings<CustomerData = RawCustomerData, VendorUsage = RawVendorUsage>
where
CustomerData: CustomerSettingsCustomerData,
VendorUsage: CustomerSettingsVendorUsage,
{
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub header: Header,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub customer_version: MonotonicCounter,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub secure_firmware_version: MonotonicCounter,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub nonsecure_firmware_version: MonotonicCounter,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub image_key_revocation_id: MonotonicCounter,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub vendor_usage: VendorUsage,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub rot_keys_status: RotKeysStatus,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(skip_deserializing)]
debug_access: DebugAccess,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub enable_fault_analysis_mode: bool,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub factory_prog_in_progress: FactorySettingsProgInProgress,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub prince_ivs: [PrinceIvCode; 3],
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
pub customer_data: CustomerData,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
sha256_hash: Sha256Hash,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub seal: bool,
}
impl CustomerSettings {
pub fn valid_activation_code(&self) -> bool {
self.header.0 == 0x95959595
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "kebab-case")]
pub struct WrappedFactorySettings<CustomerData = RawCustomerData, VendorUsage = RawVendorUsage>
where
CustomerData: FactorySettingsCustomerData,
VendorUsage: FactorySettingsVendorUsage,
{
pub factory_settings: FactorySettings<CustomerData, VendorUsage>,
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "kebab-case")]
pub struct WrappedCustomerSettings<CustomerData = RawCustomerData, VendorUsage = RawVendorUsage>
where
CustomerData: CustomerSettingsCustomerData,
VendorUsage: CustomerSettingsVendorUsage,
{
pub customer_settings: CustomerSettings<CustomerData, VendorUsage>,
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct KeystoreHeader(pub u32);
#[derive(Clone, Copy, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Keycode(#[serde(with = "BigArray")] [u8; 56]);
impl Keycode {
pub fn valid(&self) -> bool {
self.0[..4] == [0x59, 0x59, 0x59, 0x59]
}
pub fn generated_key(&self) -> bool {
self.0[4] == 1
}
pub fn user_key(&self) -> bool {
self.0[4] == 0
}
}
impl Default for Keycode {
fn default() -> Self {
Keycode([0u8; 56])
}
}
impl fmt::Debug for Keycode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format_bytes(&self.0, f)
}
}
impl AsRef<[u8]> for Keycode {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
#[derive(Clone, Copy, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct ActivationCode(#[serde(with = "BigArray")] [u8; 1192]);
impl Default for ActivationCode {
fn default() -> Self {
ActivationCode([0u8; 1192])
}
}
impl fmt::Debug for ActivationCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format_bytes(&self.0, f)
}
}
impl AsRef<[u8]> for ActivationCode {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct Keystore {
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub header: KeystoreHeader,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub puf_discharge_time_milliseconds: u32,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
pub activation_code: ActivationCode,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
pub secure_boot_kek: Keycode,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
pub user_key: Keycode,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
pub unique_device_secret: Keycode,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
pub prince_region_0: Keycode,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
pub prince_region_1: Keycode,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
#[serde(serialize_with = "hex_serialize")]
pub prince_region_2: Keycode,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct NxpArea {
uuid: u128,
}
impl Keystore {
pub fn to_bytes(&self) -> [u8; 3 * 512] {
let mut buf = [0u8; 3 * 512];
let mut cursor = buf.as_mut();
cursor.write_all(&self.header.0.to_le_bytes()).ok();
cursor
.write_all(&self.puf_discharge_time_milliseconds.to_le_bytes())
.ok();
cursor.write_all(&self.activation_code.0).ok();
cursor.write_all(&self.secure_boot_kek.0).ok();
cursor.write_all(&self.user_key.0).ok();
cursor.write_all(&self.unique_device_secret.0).ok();
cursor.write_all(&self.prince_region_0.0).ok();
cursor.write_all(&self.prince_region_1.0).ok();
cursor.write_all(&self.prince_region_2.0).ok();
assert!(cursor.is_empty());
buf
}
}
fn parse_keystore(input: &[u8]) -> IResult<&[u8], Keystore> {
let (input, header) = le_u32(input)?;
let (input, puf_discharge_time_milliseconds) = le_u32(input)?;
let (input, activation_code) = take(1192usize)(input)?;
let (input, secure_boot_kek) = take(56u8)(input)?;
let (input, user_key) = take(56u8)(input)?;
let (input, unique_device_secret) = take(56u8)(input)?;
let (input, prince_region_0) = take(56u8)(input)?;
let (input, prince_region_1) = take(56u8)(input)?;
let (input, prince_region_2) = take(56u8)(input)?;
let keystore = Keystore {
header: KeystoreHeader(header),
puf_discharge_time_milliseconds,
activation_code: ActivationCode(activation_code.try_into().unwrap()),
secure_boot_kek: Keycode(secure_boot_kek.try_into().unwrap()),
user_key: Keycode(user_key.try_into().unwrap()),
unique_device_secret: Keycode(unique_device_secret.try_into().unwrap()),
prince_region_0: Keycode(prince_region_0.try_into().unwrap()),
prince_region_1: Keycode(prince_region_1.try_into().unwrap()),
prince_region_2: Keycode(prince_region_2.try_into().unwrap()),
};
Ok((input, keystore))
}
impl<CustomerData, VendorUsage> FactorySettings<CustomerData, VendorUsage>
where
CustomerData: FactorySettingsCustomerData,
VendorUsage: FactorySettingsVendorUsage,
{
pub fn to_bytes(&mut self) -> anyhow::Result<[u8; 512]> {
let mut buf = [0u8; 512];
let mut cursor = buf.as_mut();
cursor.write_all(&u32::from(self.boot_configuration).to_le_bytes())?;
cursor.write_all(&[0u8; 4])?;
cursor.write_all(&self.usb_id.vid.to_le_bytes())?;
cursor.write_all(&self.usb_id.pid.to_le_bytes())?;
cursor.write_all(&[0u8; 4])?;
let [fixed, disabled]: [u32; 2] = DebugSettings::from(self.debug_access).into();
cursor.write_all(&fixed.to_le_bytes())?;
cursor.write_all(&disabled.to_le_bytes())?;
cursor.write_all(&self.vendor_usage.into().to_le_bytes())?;
cursor.write_all(&u32::from(self.secure_boot_configuration).to_le_bytes())?;
cursor.write_all(&u32::from(self.prince_configuration).to_le_bytes())?;
cursor.write_all(&self.prince_subregions[0].bits.to_le_bytes())?;
cursor.write_all(&self.prince_subregions[1].bits.to_le_bytes())?;
cursor.write_all(&self.prince_subregions[2].bits.to_le_bytes())?;
cursor.write_all(&[0u8; 32])?;
cursor.write_all(&self.rot_fingerprint.0)?;
cursor.write_all(&[0u8; 144])?;
cursor.write_all(self.customer_data.as_ref())?;
assert_eq!(cursor.len(), 32);
if self.seal {
info!("Sealing factory page!");
let mut hasher = sha2::Sha256::new();
hasher.update(&buf[0..480]);
self.sha256_hash = Sha256Hash(hasher.finalize().try_into().unwrap());
buf[480..512].as_mut().write_all(&self.sha256_hash.0).ok();
}
Ok(buf)
}
}
fn parse_factory<
CustomerData: FactorySettingsCustomerData,
VendorUsage: FactorySettingsVendorUsage,
>(
input: &[u8],
) -> IResult<&[u8], FactorySettings<CustomerData, VendorUsage>> {
let (input, boot_cfg) = le_u32(input)?;
let (input, _spi_flash_cfg) = le_u32(input)?;
assert_eq!(_spi_flash_cfg, 0);
let (input, usb_id) = le_u32(input)?;
let (input, _sdio_cfg) = le_u32(input)?;
assert_eq!(_sdio_cfg, 0);
let (input, cc_socu_pin) = le_u32(input)?;
let (input, cc_socu_default) = le_u32(input)?;
let (input, vendor_usage) = le_u32(input)?;
let (input, secure_boot_cfg) = le_u32(input)?;
let (input, prince_cfg) = le_u32(input)?;
let (input, prince_sr_0) = le_u32(input)?;
let (input, prince_sr_1) = le_u32(input)?;
let (input, prince_sr_2) = le_u32(input)?;
let (input, _) = take(8 * 4u8)(input)?;
let (input, rot_fingerprint) = take(32u8)(input)?;
let (input, _) = take(9 * 4 * 4u8)(input)?;
let (input, customer_data) = take(14 * 4 * 4u8)(input)?;
let (input, sha256_hash) = take(32u8)(input)?;
let factory = FactorySettings {
boot_configuration: BootConfiguration::from(boot_cfg),
usb_id: UsbId::from(usb_id),
debug_access: DebugSettings::from([cc_socu_pin, cc_socu_default]).into(),
vendor_usage: VendorUsage::from(vendor_usage),
secure_boot_configuration: SecureBootConfiguration::from(secure_boot_cfg),
prince_configuration: PrinceConfiguration::from(prince_cfg),
prince_subregions: [
PrinceSubregion::from_bits_truncate(prince_sr_0),
PrinceSubregion::from_bits_truncate(prince_sr_1),
PrinceSubregion::from_bits_truncate(prince_sr_2),
],
rot_fingerprint: Sha256Hash(rot_fingerprint.try_into().unwrap()),
customer_data: CustomerData::from(customer_data.try_into().unwrap()),
sha256_hash: Sha256Hash(sha256_hash.try_into().unwrap()),
seal: false,
};
Ok((input, factory))
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[repr(u8)]
pub enum BootSpeed {
Nxp = 0,
#[serde(rename = "96MHz")]
Fro96 = 1,
#[serde(rename = "48MHz")]
Fro48 = 2,
Reserved = 3,
}
impl Default for BootSpeed {
fn default() -> Self {
Self::Nxp
}
}
impl From<u8> for BootSpeed {
fn from(value: u8) -> Self {
use BootSpeed::*;
match value {
0b00 => Nxp,
0b01 => Fro96,
0b10 => Fro48,
_ => Reserved,
}
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum IspMode {
Auto,
Usb,
Uart,
Spi,
I2c,
FallthroughDisabled,
Reserved(u8),
}
impl Default for IspMode {
fn default() -> Self {
Self::Auto
}
}
impl From<u8> for IspMode {
fn from(value: u8) -> Self {
use IspMode::*;
match value {
0b000 => Auto,
0b001 => Usb,
0b010 => Uart,
0b011 => Spi,
0b100 => I2c,
0b111 => FallthroughDisabled,
value => Reserved(value),
}
}
}
impl From<IspMode> for u8 {
fn from(mode: IspMode) -> u8 {
use IspMode::*;
match mode {
Auto => 0,
Usb => 1,
Uart => 2,
Spi => 3,
I2c => 4,
FallthroughDisabled => 5,
Reserved(value) => value,
}
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "kebab-case")]
pub struct BootConfiguration {
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub failure_port: u8,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub failure_pin: u8,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub speed: BootSpeed,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub mode: IspMode,
}
impl From<u32> for BootConfiguration {
fn from(word: u32) -> Self {
Self {
failure_port: ((word >> 24) & 0b11) as u8,
failure_pin: ((word >> 27) & 0b11111) as u8,
speed: BootSpeed::from(((word >> 7) & 0b11) as u8),
mode: IspMode::from(((word >> 4) & 0b111) as u8),
}
}
}
impl From<BootConfiguration> for u32 {
fn from(cfg: BootConfiguration) -> u32 {
let mut word = 0u32;
word |= ((cfg.failure_port & 0b11) as u32) << 24;
word |= ((cfg.failure_pin & 0b11111) as u32) << 27;
word |= (cfg.speed as u8 as u32) << 7;
word |= (u8::from(cfg.mode) as u32) << 4;
word
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct UsbId {
pub vid: u16,
pub pid: u16,
}
impl Default for UsbId {
fn default() -> Self {
Self { vid: 0, pid: 0 }
}
}
impl From<u32> for UsbId {
fn from(word: u32) -> Self {
Self {
vid: word as _,
pid: (word >> 16) as _,
}
}
}
fn multibool(bits: u32) -> bool {
match bits {
0b00 => false,
0b01 | 0b10 | 0b11 => true,
_ => panic!(),
}
}
fn boolmulti(value: bool) -> u32 {
match value {
false => 0,
true => 0b11,
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[repr(u8)]
pub enum TrustzoneMode {
FromImageHeader = 0b00,
DisabledBootToNonsecure = 0b01,
EnabledBootToSecure = 0b10,
PresetTrustzoneCheckerFromImageHeader = 0b11,
}
impl Default for TrustzoneMode {
fn default() -> Self {
Self::FromImageHeader
}
}
impl From<u32> for TrustzoneMode {
fn from(value: u32) -> Self {
use TrustzoneMode::*;
match value {
0b00 => FromImageHeader,
0b01 => DisabledBootToNonsecure,
0b10 => EnabledBootToSecure,
0b11 => PresetTrustzoneCheckerFromImageHeader,
_ => panic!(),
}
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "kebab-case")]
pub struct SecureBootConfiguration {
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub secure_boot_enabled: bool,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub puf_enrollment_disabled: bool,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub puf_keycode_generation_disabled: bool,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub trustzone_mode: TrustzoneMode,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub dice_computation_disabled: bool,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub include_factory_area_in_dice_computation: bool,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub include_nxp_area_in_dice_computation: bool,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub include_security_epoch_area_in_dice_computation: bool,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub use_rsa4096_keys: bool,
}
impl From<u32> for SecureBootConfiguration {
fn from(word: u32) -> Self {
Self {
secure_boot_enabled: multibool((word >> 30) & 0b11),
puf_enrollment_disabled: multibool((word >> 12) & 0b11),
puf_keycode_generation_disabled: multibool((word >> 10) & 0b11),
trustzone_mode: TrustzoneMode::from((word >> 8) & 0b11),
dice_computation_disabled: multibool((word >> 6) & 0b11),
include_security_epoch_area_in_dice_computation: multibool((word >> 14) & 0b11),
include_factory_area_in_dice_computation: multibool((word >> 4) & 0b11),
include_nxp_area_in_dice_computation: multibool((word >> 2) & 0b11),
use_rsa4096_keys: multibool((word >> 0) & 0b11),
}
}
}
impl From<SecureBootConfiguration> for u32 {
fn from(cfg: SecureBootConfiguration) -> u32 {
let mut word = 0u32;
word |= boolmulti(cfg.secure_boot_enabled) << 30;
word |= boolmulti(cfg.puf_enrollment_disabled) << 12;
word |= boolmulti(cfg.puf_keycode_generation_disabled) << 10;
word |= (cfg.trustzone_mode as u8 as u32) << 8;
word |= boolmulti(cfg.dice_computation_disabled) << 6;
word |= boolmulti(cfg.include_security_epoch_area_in_dice_computation) << 14;
word |= boolmulti(cfg.include_factory_area_in_dice_computation) << 4;
word |= boolmulti(cfg.include_nxp_area_in_dice_computation) << 2;
word |= boolmulti(cfg.use_rsa4096_keys) << 0;
word
}
}
impl From<PrinceConfiguration> for u32 {
fn from(cfg: PrinceConfiguration) -> u32 {
let mut word = 0u32;
word |= boolmulti(cfg.erase_checks[0]) << 28;
word |= boolmulti(cfg.erase_checks[0]) << 26;
word |= boolmulti(cfg.erase_checks[0]) << 24;
word |= boolmulti(cfg.locked[0]) << 20;
word |= boolmulti(cfg.locked[0]) << 18;
word |= boolmulti(cfg.locked[0]) << 16;
word |= (cfg.addresses[0] as u32) << 8;
word |= (cfg.addresses[1] as u32) << 4;
word |= (cfg.addresses[2] as u32) << 0;
word
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct PrinceConfiguration {
pub erase_checks: [bool; 3],
pub locked: [bool; 3],
pub addresses: [u8; 3],
}
impl From<u32> for PrinceConfiguration {
fn from(word: u32) -> Self {
Self {
erase_checks: [
multibool((word >> 28) & 0b11),
multibool((word >> 26) & 0b11),
multibool((word >> 24) & 0b11),
],
locked: [
multibool((word >> 20) & 0b11),
multibool((word >> 18) & 0b11),
multibool((word >> 16) & 0b11),
],
addresses: [
((word >> 8) & 0xF) as _,
((word >> 4) & 0xF) as _,
((word >> 0) & 0xF) as _,
],
}
}
}
bitflags::bitflags! {
#[derive(Default, Deserialize, Serialize)]
pub struct PrinceSubregion: u32 {
const REGION_00 = 1 << 0;
const REGION_01 = 1 << 1;
const REGION_02 = 1 << 2;
const REGION_03 = 1 << 3;
const REGION_04 = 1 << 4;
const REGION_05 = 1 << 5;
const REGION_06 = 1 << 6;
const REGION_07 = 1 << 7;
const REGION_08 = 1 << 8;
const REGION_09 = 1 << 9;
const REGION_10 = 1 << 10;
const REGION_11 = 1 << 11;
const REGION_12 = 1 << 12;
const REGION_13 = 1 << 13;
const REGION_14 = 1 << 14;
const REGION_15 = 1 << 15;
const REGION_16 = 1 << 16;
const REGION_17 = 1 << 17;
const REGION_18 = 1 << 18;
const REGION_19 = 1 << 19;
const REGION_20 = 1 << 20;
const REGION_21 = 1 << 21;
const REGION_22 = 1 << 22;
const REGION_23 = 1 << 23;
const REGION_24 = 1 << 24;
const REGION_25 = 1 << 25;
const REGION_26 = 1 << 26;
const REGION_27 = 1 << 27;
const REGION_28 = 1 << 28;
const REGION_29 = 1 << 29;
const REGION_30 = 1 << 30;
const REGION_31 = 1 << 31;
}
}
impl core::convert::TryFrom<&[u8]> for ProtectedFlash {
type Error = ();
fn try_from(input: &[u8]) -> ::std::result::Result<Self, Self::Error> {
let factory_settings = FactorySettings::try_from(&input[3 * 512..4 * 512]).unwrap();
let customer = CustomerSettingsArea::try_from(&input[..3 * 512]).unwrap();
let keystore = Keystore::try_from(&input[4 * 512..7 * 512]).unwrap();
let pfr = ProtectedFlash {
customer,
factory_settings,
keystore,
};
Ok(pfr)
}
}
pub trait CustomerSettingsCustomerData:
AsRef<[u8]> + fmt::Debug + Default + From<[u8; 14 * 4 * 4]> + PartialEq
{
}
pub trait FactorySettingsCustomerData:
AsRef<[u8]> + fmt::Debug + Default + From<[u8; 14 * 4 * 4]> + PartialEq
{
}
#[derive(Clone, Copy, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct RawCustomerData(#[serde(with = "BigArray")] [u8; 4 * 4 * 14]);
impl AsRef<[u8]> for RawCustomerData {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl Default for RawCustomerData {
fn default() -> Self {
RawCustomerData([0u8; 224])
}
}
impl fmt::Debug for RawCustomerData {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
format_bytes(&self.0, f)
}
}
impl From<[u8; 14 * 4 * 4]> for RawCustomerData {
fn from(bytes: [u8; 224]) -> Self {
Self(bytes)
}
}
impl CustomerSettingsCustomerData for RawCustomerData {}
impl FactorySettingsCustomerData for RawCustomerData {}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct CustomerSettingsArea<CustomerData = RawCustomerData, VendorUsage = RawVendorUsage>
where
CustomerData: CustomerSettingsCustomerData,
VendorUsage: CustomerSettingsVendorUsage,
{
pub scratch: CustomerSettings<CustomerData, VendorUsage>,
pub ping: CustomerSettings<CustomerData, VendorUsage>,
pub pong: CustomerSettings<CustomerData, VendorUsage>,
}
impl core::convert::TryFrom<&[u8]> for CustomerSettingsArea {
type Error = ();
fn try_from(input: &[u8]) -> ::std::result::Result<Self, Self::Error> {
let scratch = CustomerSettings::try_from(&input[..512]).unwrap();
let ping = CustomerSettings::try_from(&input[512..2 * 512]).unwrap();
let pong = CustomerSettings::try_from(&input[2 * 512..3 * 512]).unwrap();
let customer_settings = CustomerSettingsArea {
scratch,
ping,
pong,
};
Ok(customer_settings)
}
}
impl<CustomerData, VendorUsage> CustomerSettingsArea<CustomerData, VendorUsage>
where
CustomerData: CustomerSettingsCustomerData + Clone,
VendorUsage: CustomerSettingsVendorUsage + Clone,
{
pub fn most_recent(&self) -> CustomerSettings<CustomerData, VendorUsage> {
if self.ping.customer_version > self.pong.customer_version {
self.ping.clone()
} else {
self.pong.clone()
}
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct Header(u32);
pub trait CustomerSettingsVendorUsage:
Clone + Copy + fmt::Debug + Default + From<u32> + Into<u32> + PartialEq
{
}
pub trait FactorySettingsVendorUsage:
Clone + Copy + fmt::Debug + Default + From<u32> + Into<u32> + PartialEq
{
}
#[derive(Clone, Copy, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct RawVendorUsage(u32);
impl fmt::Debug for RawVendorUsage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("RawVendorUsage").field(&self.0).finish()
}
}
impl From<RawVendorUsage> for u32 {
fn from(usage: RawVendorUsage) -> u32 {
usage.0
}
}
impl From<u32> for RawVendorUsage {
fn from(word: u32) -> Self {
Self(word)
}
}
impl CustomerSettingsVendorUsage for RawVendorUsage {}
impl FactorySettingsVendorUsage for RawVendorUsage {}
#[derive(Clone, Copy, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct FactorySettingsProgInProgress(u32);
impl fmt::Debug for FactorySettingsProgInProgress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.0 {
0x0000_0000 => f.write_fmt(format_args!("empty (0x{:x})", 0)),
0x5CC5_5AA5 => f.write_str("CMPA page programming ongoing"),
value => f.write_fmt(format_args!("unknown value {:x}", value)),
}
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct RotKeysStatus([RotKeyStatus; 4]);
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct PrinceIvCode(#[serde(with = "BigArray")] [u8; 56]);
impl Default for PrinceIvCode {
fn default() -> Self {
PrinceIvCode([0u8; 56])
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
pub struct MonotonicCounter(u32);
impl MonotonicCounter {
fn from(value: u32) -> Self {
Self(value)
}
pub fn increment(&mut self) {
self.0 += 1;
}
pub fn read(&self) -> u32 {
self.0
}
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[repr(u8)]
pub enum RotKeyStatus {
Invalid = 0,
Enabled = 1,
Revoked = 3,
}
impl Default for RotKeyStatus {
fn default() -> Self {
Self::Invalid
}
}
impl From<u8> for RotKeyStatus {
fn from(value: u8) -> Self {
use RotKeyStatus::*;
match value {
0b00 => Invalid,
0b01 => Enabled,
0b10 | 0b11 => Revoked,
_ => Invalid,
}
}
}
impl From<RotKeysStatus> for u32 {
fn from(statii: RotKeysStatus) -> u32 {
let mut value: u32 = 0;
for (i, status) in statii.0.iter().enumerate() {
value += (*status as u8 as u32) << (2 * i);
}
value
}
}
impl From<u32> for RotKeysStatus {
fn from(value: u32) -> Self {
let value = value as u8;
let key_0_status = RotKeyStatus::from((value >> 0) & 0b11);
let key_1_status = RotKeyStatus::from((value >> 2) & 0b11);
let key_2_status = RotKeyStatus::from((value >> 4) & 0b11);
let key_3_status = RotKeyStatus::from((value >> 6) & 0b11);
Self([key_0_status, key_1_status, key_2_status, key_3_status])
}
}
impl<CustomerData, VendorUsage> CustomerSettings<CustomerData, VendorUsage>
where
CustomerData: CustomerSettingsCustomerData,
VendorUsage: CustomerSettingsVendorUsage,
{
pub fn debug_settings(&self) -> DebugSettings {
self.debug_access.into()
}
pub fn to_bytes(&mut self) -> anyhow::Result<[u8; 512]> {
let mut buf = [0u8; 512];
let mut cursor = buf.as_mut();
cursor.write_all(&self.header.0.to_le_bytes())?;
cursor.write_all(&self.customer_version.0.to_le_bytes())?;
cursor.write_all(&self.secure_firmware_version.0.to_le_bytes())?;
cursor.write_all(&self.nonsecure_firmware_version.0.to_le_bytes())?;
cursor.write_all(&self.image_key_revocation_id.0.to_le_bytes())?;
cursor.write_all(&[0u8; 4])?;
cursor.write_all(&u32::from(self.rot_keys_status).to_le_bytes())?;
cursor.write_all(&self.vendor_usage.into().to_le_bytes())?;
cursor.write_all(&0u32.to_le_bytes())?;
cursor.write_all(&0u32.to_le_bytes())?;
let enable_fa_mode: u32 = match self.enable_fault_analysis_mode {
true => 0xC33C_A55A,
false => 0,
};
cursor.write_all(&enable_fa_mode.to_le_bytes())?;
cursor.write_all(&[0u8; 4])?;
cursor.write_all(&self.prince_ivs[0].0)?;
cursor.write_all(&self.prince_ivs[1].0)?;
cursor.write_all(&self.prince_ivs[2].0)?;
cursor.write_all(&[0u8; 40])?;
cursor.write_all(self.customer_data.as_ref())?;
assert_eq!(cursor.len(), 32);
if self.seal {
info!("Sealing customer page!");
let mut hasher = sha2::Sha256::new();
hasher.update(&buf[0..480]);
self.sha256_hash = Sha256Hash(hasher.finalize().try_into().unwrap());
buf[480..512].as_mut().write_all(&self.sha256_hash.0).ok();
}
Ok(buf)
}
}
fn parse_customer_page<
CustomerData: CustomerSettingsCustomerData,
VendorUsage: CustomerSettingsVendorUsage,
>(
input: &[u8],
) -> IResult<&[u8], CustomerSettings<CustomerData, VendorUsage>> {
assert!(input.len() == 512);
let (input, header) = le_u32(input)?;
let (input, customer_version) = le_u32(input)?;
let (input, secure_firmware_version) = le_u32(input)?;
let (input, nonsecure_firmware_version) = le_u32(input)?;
let (input, image_key_revocation_id) = le_u32(input)?;
let (input, _) = take(4u8)(input)?;
let (input, rot_keys_status) = le_u32(input)?;
let (input, vendor_usage) = le_u32(input)?;
let (input, dcfg_cc_socu_ns_pin) = le_u32(input)?;
let (input, dcfg_cc_socu_ns_default) = le_u32(input)?;
let (input, enable_fa) = le_u32(input)?;
let (input, factory_prog_in_progress) = le_u32(input)?;
let (input, prince_iv_code0) = take(14 * 4u8)(input)?;
debug!("prince IV code 0 = {}", hex_str!(prince_iv_code0));
let (input, prince_iv_code1) = take(14 * 4u8)(input)?;
let (input, prince_iv_code2) = take(14 * 4u8)(input)?;
let (input, _reserved) = take(10 * 4u8)(input)?;
debug!("reserved raw = {}", hex_str!(_reserved));
let (input, customer_data) = take(56 * 4u8)(input)?;
debug!(
"customer_data all zero = {}",
customer_data.iter().all(|x| *x == 0)
);
debug!("customer_data raw = {}", hex_str!(customer_data));
let (input, sha256_hash) = take(32u8)(input)?;
assert!(input.is_empty());
let page = CustomerSettings {
header: Header(header),
customer_version: MonotonicCounter::from(customer_version),
secure_firmware_version: MonotonicCounter::from(secure_firmware_version),
nonsecure_firmware_version: MonotonicCounter::from(nonsecure_firmware_version),
image_key_revocation_id: MonotonicCounter::from(image_key_revocation_id),
vendor_usage: VendorUsage::from(vendor_usage),
rot_keys_status: RotKeysStatus::from(rot_keys_status),
debug_access: DebugSettings::from([dcfg_cc_socu_ns_pin, dcfg_cc_socu_ns_default]).into(),
enable_fault_analysis_mode: enable_fa != 0,
factory_prog_in_progress: FactorySettingsProgInProgress(factory_prog_in_progress),
prince_ivs: [
PrinceIvCode(prince_iv_code0.try_into().unwrap()),
PrinceIvCode(prince_iv_code1.try_into().unwrap()),
PrinceIvCode(prince_iv_code2.try_into().unwrap()),
],
customer_data: CustomerData::from(customer_data.try_into().unwrap()),
sha256_hash: Sha256Hash(sha256_hash.try_into().unwrap()),
seal: false,
};
Ok((input, page))
}
impl<CustomerData, VendorUsage> core::convert::TryFrom<&[u8]>
for CustomerSettings<CustomerData, VendorUsage>
where
CustomerData: CustomerSettingsCustomerData,
VendorUsage: CustomerSettingsVendorUsage,
{
type Error = ();
fn try_from(input: &[u8]) -> ::std::result::Result<Self, Self::Error> {
let (_input, page) = parse_customer_page(input).unwrap();
Ok(page)
}
}
impl<CustomerData, VendorUsage> core::convert::TryFrom<&[u8]>
for FactorySettings<CustomerData, VendorUsage>
where
CustomerData: FactorySettingsCustomerData,
VendorUsage: FactorySettingsVendorUsage,
{
type Error = ();
fn try_from(input: &[u8]) -> ::std::result::Result<Self, Self::Error> {
let (_input, page) = parse_factory(input).unwrap();
Ok(page)
}
}
impl core::convert::TryFrom<&[u8]> for Keystore {
type Error = ();
fn try_from(input: &[u8]) -> ::std::result::Result<Self, Self::Error> {
let (_input, keystore) = parse_keystore(input).unwrap();
Ok(keystore)
}
}