use crate::cbor::{
self, Cbor, Decode, Encode, MapDecode, MapEncode, MapEncodeBuffer, MapEntryAccess,
};
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct Ueid {
#[cbor(key = 256)]
pub ueid: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Oemid {
value: OemidValue,
}
impl Oemid {
pub fn new_random(id: [u8; 16]) -> Self {
Self {
value: OemidValue::Random(id),
}
}
pub fn new_ieee(id: [u8; 3]) -> Self {
Self {
value: OemidValue::Ieee(id),
}
}
pub fn new_pen(pen: u64) -> Self {
Self {
value: OemidValue::Pen(pen),
}
}
pub fn random(&self) -> Option<[u8; 16]> {
match self.value {
OemidValue::Random(id) => Some(id),
_ => None,
}
}
pub fn ieee(&self) -> Option<[u8; 3]> {
match self.value {
OemidValue::Ieee(id) => Some(id),
_ => None,
}
}
pub fn pen(&self) -> Option<u64> {
match self.value {
OemidValue::Pen(pen) => Some(pen),
_ => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
enum OemidValue {
Random([u8; 16]),
Ieee([u8; 3]),
Pen(u64),
}
impl Encode for OemidValue {
fn encode_cbor_to(&self, buf: &mut Vec<u8>) -> Result<(), cbor::Error> {
match self {
OemidValue::Random(id) => id.as_slice().encode_cbor_to(buf),
OemidValue::Ieee(id) => id.as_slice().encode_cbor_to(buf),
OemidValue::Pen(pen) => pen.encode_cbor_to(buf),
}
}
}
impl Decode for OemidValue {
fn decode_cbor(data: &[u8]) -> Result<Self, cbor::Error> {
let mut dec = cbor::Decoder::new(data);
let result = Self::decode_cbor_notrail(&mut dec)?;
dec.finish()?;
Ok(result)
}
fn decode_cbor_notrail(dec: &mut cbor::Decoder<'_>) -> Result<Self, cbor::Error> {
if dec.peek_uint().is_ok() {
let pen = dec.decode_uint()?;
return Ok(OemidValue::Pen(pen));
}
let bytes = dec.decode_bytes()?;
match bytes.len() {
3 => {
let mut id = [0u8; 3];
id.copy_from_slice(&bytes);
Ok(OemidValue::Ieee(id))
}
16 => {
let mut id = [0u8; 16];
id.copy_from_slice(&bytes);
Ok(OemidValue::Random(id))
}
n => Err(cbor::Error::DecodeFailed(format!(
"oemid: unexpected bstr length {n}"
))),
}
}
}
impl Encode for Oemid {
fn encode_cbor_to(&self, buf: &mut Vec<u8>) -> Result<(), cbor::Error> {
let mut enc = MapEncodeBuffer::new(1);
<Self as MapEncode>::encode_map(self, &mut enc)?;
enc.finish_to(buf)
}
}
impl Decode for Oemid {
fn decode_cbor(data: &[u8]) -> Result<Self, cbor::Error> {
let mut dec = cbor::Decoder::new(data);
let result = Self::decode_cbor_notrail(&mut dec)?;
dec.finish()?;
Ok(result)
}
fn decode_cbor_notrail(dec: &mut cbor::Decoder<'_>) -> Result<Self, cbor::Error> {
let entries = cbor::decode_map_entries_slices_notrail(dec)?;
let mut remaining = cbor::MapEntries::new(entries);
let value = <Self as MapDecode>::decode_map(&mut remaining)?;
if !remaining.is_empty() {
let unknown: Vec<i64> = remaining.remaining_keys();
return Err(cbor::Error::DecodeFailed(format!(
"unknown CBOR map keys: {unknown:?}"
)));
}
Ok(value)
}
}
impl MapEncode for Oemid {
fn encode_map(&self, enc: &mut MapEncodeBuffer) -> Result<(), cbor::Error> {
enc.push(258, &self.value)
}
}
impl MapDecode for Oemid {
fn cbor_map_keys() -> &'static [i64] {
&[258]
}
fn decode_map<'a, E: MapEntryAccess<'a>>(entries: &mut E) -> Result<Self, cbor::Error> {
let raw = entries
.take(258)
.ok_or(cbor::Error::DecodeFailed("missing required key 258".into()))?;
let value = OemidValue::decode_cbor(raw)?;
Ok(Self { value })
}
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct HwModel {
#[cbor(key = 259)]
pub hw_model: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HwVersion {
version: String,
}
impl HwVersion {
pub fn new(version: String) -> Self {
Self { version }
}
pub fn version(&self) -> &str {
&self.version
}
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
#[cbor(array)]
struct VersionArray {
version: String,
}
impl Encode for HwVersion {
fn encode_cbor_to(&self, buf: &mut Vec<u8>) -> Result<(), cbor::Error> {
let mut enc = MapEncodeBuffer::new(1);
<Self as MapEncode>::encode_map(self, &mut enc)?;
enc.finish_to(buf)
}
}
impl Decode for HwVersion {
fn decode_cbor(data: &[u8]) -> Result<Self, cbor::Error> {
let mut dec = cbor::Decoder::new(data);
let result = Self::decode_cbor_notrail(&mut dec)?;
dec.finish()?;
Ok(result)
}
fn decode_cbor_notrail(dec: &mut cbor::Decoder<'_>) -> Result<Self, cbor::Error> {
let entries = cbor::decode_map_entries_slices_notrail(dec)?;
let mut remaining = cbor::MapEntries::new(entries);
let value = <Self as MapDecode>::decode_map(&mut remaining)?;
if !remaining.is_empty() {
let unknown: Vec<i64> = remaining.remaining_keys();
return Err(cbor::Error::DecodeFailed(format!(
"unknown CBOR map keys: {unknown:?}"
)));
}
Ok(value)
}
}
impl MapEncode for HwVersion {
fn encode_map(&self, enc: &mut MapEncodeBuffer) -> Result<(), cbor::Error> {
let arr = VersionArray {
version: self.version.clone(),
};
enc.push(260, &arr)
}
}
impl MapDecode for HwVersion {
fn cbor_map_keys() -> &'static [i64] {
&[260]
}
fn decode_map<'a, E: MapEntryAccess<'a>>(entries: &mut E) -> Result<Self, cbor::Error> {
let raw = entries
.take(260)
.ok_or(cbor::Error::DecodeFailed("missing required key 260".into()))?;
let arr = VersionArray::decode_cbor(raw)?;
Ok(Self {
version: arr.version,
})
}
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct Uptime {
#[cbor(key = 261)]
pub uptime: u64,
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct OemBoot {
#[cbor(key = 262)]
pub oem_boot: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u64)]
pub enum DebugState {
Enabled = 0,
Disabled = 1,
DisabledSinceBoot = 2,
DisabledPermanently = 3,
DisabledFullyPermanently = 4,
}
impl Encode for DebugState {
fn encode_cbor_to(&self, buf: &mut Vec<u8>) -> Result<(), cbor::Error> {
(*self as u64).encode_cbor_to(buf)
}
}
impl Decode for DebugState {
fn decode_cbor(data: &[u8]) -> Result<Self, cbor::Error> {
let mut dec = cbor::Decoder::new(data);
let result = Self::decode_cbor_notrail(&mut dec)?;
dec.finish()?;
Ok(result)
}
fn decode_cbor_notrail(dec: &mut cbor::Decoder<'_>) -> Result<Self, cbor::Error> {
let value = dec.decode_uint()?;
match value {
0 => Ok(DebugState::Enabled),
1 => Ok(DebugState::Disabled),
2 => Ok(DebugState::DisabledSinceBoot),
3 => Ok(DebugState::DisabledPermanently),
4 => Ok(DebugState::DisabledFullyPermanently),
_ => Err(cbor::Error::DecodeFailed(format!(
"invalid debug state: {value}"
))),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct DebugStatus {
#[cbor(key = 263)]
pub debug_status: DebugState,
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct BootCount {
#[cbor(key = 267)]
pub boot_count: u64,
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct BootSeed {
#[cbor(key = 268)]
pub boot_seed: Vec<u8>,
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct SwName {
#[cbor(key = 270)]
pub sw_name: String,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SwVersion {
version: String,
}
impl SwVersion {
pub fn new(version: String) -> Self {
Self { version }
}
pub fn version(&self) -> &str {
&self.version
}
}
impl Encode for SwVersion {
fn encode_cbor_to(&self, buf: &mut Vec<u8>) -> Result<(), cbor::Error> {
let mut enc = MapEncodeBuffer::new(1);
<Self as MapEncode>::encode_map(self, &mut enc)?;
enc.finish_to(buf)
}
}
impl Decode for SwVersion {
fn decode_cbor(data: &[u8]) -> Result<Self, cbor::Error> {
let mut dec = cbor::Decoder::new(data);
let result = Self::decode_cbor_notrail(&mut dec)?;
dec.finish()?;
Ok(result)
}
fn decode_cbor_notrail(dec: &mut cbor::Decoder<'_>) -> Result<Self, cbor::Error> {
let entries = cbor::decode_map_entries_slices_notrail(dec)?;
let mut remaining = cbor::MapEntries::new(entries);
let value = <Self as MapDecode>::decode_map(&mut remaining)?;
if !remaining.is_empty() {
let unknown: Vec<i64> = remaining.remaining_keys();
return Err(cbor::Error::DecodeFailed(format!(
"unknown CBOR map keys: {unknown:?}"
)));
}
Ok(value)
}
}
impl MapEncode for SwVersion {
fn encode_map(&self, enc: &mut MapEncodeBuffer) -> Result<(), cbor::Error> {
let arr = VersionArray {
version: self.version.clone(),
};
enc.push(271, &arr)
}
}
impl MapDecode for SwVersion {
fn cbor_map_keys() -> &'static [i64] {
&[271]
}
fn decode_map<'a, E: MapEntryAccess<'a>>(entries: &mut E) -> Result<Self, cbor::Error> {
let raw = entries
.take(271)
.ok_or(cbor::Error::DecodeFailed("missing required key 271".into()))?;
let arr = VersionArray::decode_cbor(raw)?;
Ok(Self {
version: arr.version,
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(u64)]
pub enum Use {
Generic = 1,
Registration = 2,
Provisioning = 3,
CertIssuance = 4,
ProofOfPossession = 5,
}
impl Encode for Use {
fn encode_cbor_to(&self, buf: &mut Vec<u8>) -> Result<(), cbor::Error> {
(*self as u64).encode_cbor_to(buf)
}
}
impl Decode for Use {
fn decode_cbor(data: &[u8]) -> Result<Self, cbor::Error> {
let mut dec = cbor::Decoder::new(data);
let result = Self::decode_cbor_notrail(&mut dec)?;
dec.finish()?;
Ok(result)
}
fn decode_cbor_notrail(dec: &mut cbor::Decoder<'_>) -> Result<Self, cbor::Error> {
let value = dec.decode_uint()?;
match value {
1 => Ok(Use::Generic),
2 => Ok(Use::Registration),
3 => Ok(Use::Provisioning),
4 => Ok(Use::CertIssuance),
5 => Ok(Use::ProofOfPossession),
_ => Err(cbor::Error::DecodeFailed(format!(
"invalid intended use: {value}"
))),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Cbor)]
pub struct IntendedUse {
#[cbor(key = 275)]
pub intended_use: Use,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_oemid_random() {
let id: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
oemid: Oemid,
}
let orig = Token {
oemid: Oemid::new_random(id),
};
let data = cbor::encode(&orig).expect("encode");
let got = Token::decode_cbor(&data).expect("decode");
assert_eq!(got.oemid.random(), Some(id));
}
#[test]
fn test_oemid_ieee() {
let id: [u8; 3] = [0xAC, 0xDE, 0x48];
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
oemid: Oemid,
}
let orig = Token {
oemid: Oemid::new_ieee(id),
};
let data = cbor::encode(&orig).expect("encode");
let got = Token::decode_cbor(&data).expect("decode");
assert_eq!(got.oemid.ieee(), Some(id));
}
#[test]
fn test_oemid_pen() {
let pen: u64 = 76543;
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
oemid: Oemid,
}
let orig = Token {
oemid: Oemid::new_pen(pen),
};
let data = cbor::encode(&orig).expect("encode");
let got = Token::decode_cbor(&data).expect("decode");
assert_eq!(got.oemid.pen(), Some(pen));
}
#[test]
fn test_oemid_wrong_accessor() {
let o = Oemid::new_pen(42);
assert_eq!(o.random(), None);
assert_eq!(o.ieee(), None);
}
#[test]
fn test_hw_version() {
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
hw: HwVersion,
}
let orig = Token {
hw: HwVersion::new("1.2.3".into()),
};
let data = cbor::encode(&orig).expect("encode");
let got = Token::decode_cbor(&data).expect("decode");
assert_eq!(got.hw.version(), "1.2.3");
}
#[test]
fn test_sw_version() {
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
sw: SwVersion,
}
let orig = Token {
sw: SwVersion::new("4.5.6".into()),
};
let data = cbor::encode(&orig).expect("encode");
let got = Token::decode_cbor(&data).expect("decode");
assert_eq!(got.sw.version(), "4.5.6");
}
#[test]
fn test_simple_claims() {
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
ueid: Ueid,
#[cbor(embed)]
hw_model: HwModel,
#[cbor(embed)]
uptime: Uptime,
#[cbor(embed)]
oem_boot: OemBoot,
#[cbor(embed)]
debug_status: DebugStatus,
#[cbor(embed)]
boot_count: BootCount,
#[cbor(embed)]
boot_seed: BootSeed,
#[cbor(embed)]
sw_name: SwName,
#[cbor(embed)]
intended_use: IntendedUse,
}
let orig = Token {
ueid: Ueid {
ueid: vec![0x01, 0x02, 0x03],
},
hw_model: HwModel {
hw_model: b"board-v2".to_vec(),
},
uptime: Uptime { uptime: 3600 },
oem_boot: OemBoot { oem_boot: true },
debug_status: DebugStatus {
debug_status: DebugState::DisabledPermanently,
},
boot_count: BootCount { boot_count: 42 },
boot_seed: BootSeed {
boot_seed: vec![0xDE, 0xAD],
},
sw_name: SwName {
sw_name: "firmware-v3".into(),
},
intended_use: IntendedUse {
intended_use: Use::CertIssuance,
},
};
let data = cbor::encode(&orig).expect("encode");
let got = Token::decode_cbor(&data).expect("decode");
assert_eq!(got.ueid.ueid, vec![0x01, 0x02, 0x03]);
assert_eq!(got.hw_model.hw_model, b"board-v2");
assert_eq!(got.uptime.uptime, 3600);
assert!(got.oem_boot.oem_boot);
assert_eq!(
got.debug_status.debug_status,
DebugState::DisabledPermanently
);
assert_eq!(got.boot_count.boot_count, 42);
assert_eq!(got.boot_seed.boot_seed, vec![0xDE, 0xAD]);
assert_eq!(got.sw_name.sw_name, "firmware-v3");
assert_eq!(got.intended_use.intended_use, Use::CertIssuance);
}
#[test]
fn test_oemid_invalid_length() {
let mut enc = cbor::Encoder::new();
enc.encode_map_header(1);
enc.encode_int(258);
enc.encode_bytes(&[1, 2, 3, 4, 5]);
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
oemid: Oemid,
}
assert!(Token::decode_cbor(&enc.finish()).is_err());
}
#[test]
fn test_oemid_invalid_type() {
let mut enc = cbor::Encoder::new();
enc.encode_map_header(1);
enc.encode_int(258);
enc.encode_text("not-bytes");
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
oemid: Oemid,
}
assert!(Token::decode_cbor(&enc.finish()).is_err());
}
#[test]
fn test_debug_state_invalid() {
let mut enc = cbor::Encoder::new();
enc.encode_map_header(1);
enc.encode_int(263);
enc.encode_uint(99);
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
debug: DebugStatus,
}
assert!(Token::decode_cbor(&enc.finish()).is_err());
}
#[test]
fn test_use_invalid() {
let mut enc = cbor::Encoder::new();
enc.encode_map_header(1);
enc.encode_int(275);
enc.encode_uint(0);
#[derive(Debug, Cbor)]
struct Token {
#[cbor(embed)]
intended_use: IntendedUse,
}
assert!(Token::decode_cbor(&enc.finish()).is_err());
}
}