1use crate::error::Error;
10use crate::payload_util::require_at_least;
11use alloc::vec::Vec;
12
13#[derive(Debug, Clone, PartialEq, Eq)]
18pub struct PivData {
19 pub object_id: [u8; 3],
21 pub element_id: u8,
23 pub offset: u16,
25 pub data: Vec<u8>,
27}
28
29impl PivData {
30 pub fn encode(&self) -> Result<Vec<u8>, Error> {
32 let mut out = Vec::with_capacity(6 + self.data.len());
33 out.extend_from_slice(&self.object_id);
34 out.push(self.element_id);
35 out.extend_from_slice(&self.offset.to_le_bytes());
36 out.extend_from_slice(&self.data);
37 Ok(out)
38 }
39
40 pub fn decode(data: &[u8]) -> Result<Self, Error> {
42 require_at_least(data, 6, 0xA3)?;
43 let mut object_id = [0u8; 3];
44 object_id.copy_from_slice(&data[..3]);
45 Ok(Self {
46 object_id,
47 element_id: data[3],
48 offset: u16::from_le_bytes([data[4], data[5]]),
49 data: data[6..].to_vec(),
50 })
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq)]
56pub struct GenAuth {
57 pub algorithm: u8,
59 pub key_ref: u8,
61 pub auth_template: Vec<u8>,
63}
64
65impl GenAuth {
66 pub fn encode(&self) -> Result<Vec<u8>, Error> {
68 let mut out = Vec::with_capacity(2 + self.auth_template.len());
69 out.push(self.algorithm);
70 out.push(self.key_ref);
71 out.extend_from_slice(&self.auth_template);
72 Ok(out)
73 }
74
75 pub fn decode(data: &[u8]) -> Result<Self, Error> {
77 require_at_least(data, 2, 0xA4)?;
78 Ok(Self {
79 algorithm: data[0],
80 key_ref: data[1],
81 auth_template: data[2..].to_vec(),
82 })
83 }
84}
85
86#[derive(Debug, Clone, PartialEq, Eq)]
88pub struct CrAuth {
89 pub challenge: Vec<u8>,
91}
92
93impl CrAuth {
94 pub fn encode(&self) -> Result<Vec<u8>, Error> {
96 Ok(self.challenge.clone())
97 }
98
99 pub fn decode(data: &[u8]) -> Result<Self, Error> {
101 Ok(Self {
102 challenge: data.to_vec(),
103 })
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn pivdata_roundtrip() {
113 let body = PivData {
114 object_id: [0x5F, 0xC1, 0x02],
115 element_id: 0x01,
116 offset: 0x0010,
117 data: alloc::vec![0xAA, 0xBB],
118 };
119 let bytes = body.encode().unwrap();
120 assert_eq!(bytes, [0x5F, 0xC1, 0x02, 0x01, 0x10, 0x00, 0xAA, 0xBB]);
121 assert_eq!(PivData::decode(&bytes).unwrap(), body);
122 }
123
124 #[test]
125 fn pivdata_rejects_short_header() {
126 assert!(matches!(
127 PivData::decode(&[0; 5]),
128 Err(Error::PayloadTooShort { code: 0xA3, .. })
129 ));
130 }
131
132 #[test]
133 fn genauth_roundtrip() {
134 let body = GenAuth {
135 algorithm: 0x07,
136 key_ref: 0x9A,
137 auth_template: alloc::vec![0x7C, 0x02, 0x80, 0x00],
138 };
139 let bytes = body.encode().unwrap();
140 assert_eq!(bytes, [0x07, 0x9A, 0x7C, 0x02, 0x80, 0x00]);
141 assert_eq!(GenAuth::decode(&bytes).unwrap(), body);
142 }
143
144 #[test]
145 fn genauth_rejects_short() {
146 assert!(matches!(
147 GenAuth::decode(&[0x07]),
148 Err(Error::PayloadTooShort { code: 0xA4, .. })
149 ));
150 }
151
152 #[test]
153 fn crauth_passthrough() {
154 let body = CrAuth {
155 challenge: alloc::vec![0x11; 16],
156 };
157 let bytes = body.encode().unwrap();
158 assert_eq!(bytes.len(), 16);
159 assert_eq!(CrAuth::decode(&bytes).unwrap(), body);
160 }
161
162 #[test]
163 fn crauth_accepts_empty() {
164 assert_eq!(
165 CrAuth::decode(&[]).unwrap(),
166 CrAuth {
167 challenge: Vec::new()
168 }
169 );
170 }
171}