at_cryptoauth/
memory.rs

1use super::error::{Error, ErrorKind};
2use core::ops::{Range, RangeInclusive};
3use core::slice::from_ref;
4/// Zone bit 7 set: Access 32 bytes, otherwise 4 bytes.
5const ZONE_READWRITE_32: u8 = 0x80;
6
7/// A unit of data exchange is either 4 or 32 bytes.
8#[derive(Copy, Clone, Debug)]
9pub enum Size {
10    Word = 0x04,
11    Block = 0x20,
12}
13
14impl Size {
15    pub(crate) fn len(&self) -> usize {
16        match self {
17            Self::Word => Self::Word as usize,
18            Self::Block => Self::Block as usize,
19        }
20    }
21}
22
23#[derive(Copy, Clone, Debug)]
24pub enum Zone {
25    Config = 0x00,
26    Data = 0x01,
27    Otp = 0x02,
28}
29
30impl Zone {
31    // A helper method to translate a global index into block and offset.
32    pub fn locate_index(index: usize) -> (u8, u8, u8) {
33        let block = index / Size::Block.len();
34        let offset = index % Size::Block.len() / Size::Word.len();
35        let position = index % Size::Word.len();
36        (block as u8, offset as u8, position as u8)
37    }
38
39    pub(crate) fn get_slot_addr(&self, slot: Slot, block: u8) -> Result<u16, Error> {
40        match self {
41            Self::Data if slot.is_private_key() && block == 0 => Ok((slot as u16) << 3),
42            Self::Data if slot.is_certificate() && block <= 2 => {
43                Ok((slot as u16) << 3 | (block as u16) << 8)
44            }
45            _ => Err(ErrorKind::BadParam.into()),
46        }
47    }
48
49    pub(crate) fn get_addr(&self, block: u8, offset: u8) -> Result<u16, Error> {
50        if block.leading_zeros() < 3 || offset.leading_zeros() < 4 {
51            return Err(ErrorKind::BadParam.into());
52        }
53        let block = (block as u16) << 3;
54        let offset = (offset & 0x07) as u16;
55        let addr = block | offset;
56        match self {
57            Self::Config | Self::Otp => Ok(addr),
58            // Use get_slot_addr instead.
59            Self::Data => Err(ErrorKind::BadParam.into()),
60        }
61    }
62
63    pub(crate) fn encode(&self, size: Size) -> u8 {
64        match size {
65            Size::Word => *self as u8,
66            Size::Block => *self as u8 | ZONE_READWRITE_32,
67        }
68    }
69}
70
71#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
72pub enum Slot {
73    /// PrivateKey0x contains 36 bytes, taking 2 block reads.
74    PrivateKey00 = 0x00,
75    PrivateKey01 = 0x01,
76    PrivateKey02 = 0x02,
77    PrivateKey03 = 0x03,
78    PrivateKey04 = 0x04,
79    PrivateKey05 = 0x05,
80    PrivateKey06 = 0x06,
81    PrivateKey07 = 0x07,
82    /// Data08 contains 416 bytes, taking 13 block reads.
83    Data08 = 0x08,
84    /// Certificate0x contains 72 bytes, taking 3 block reads.
85    Certificate09 = 0x09,
86    Certificate0a = 0x0a,
87    Certificate0b = 0x0b,
88    Certificate0c = 0x0c,
89    Certificate0d = 0x0d,
90    Certificate0e = 0x0e,
91    Certificate0f = 0x0f,
92}
93
94impl Slot {
95    /// Check if a slot can store private keys.
96    pub fn is_private_key(&self) -> bool {
97        *self <= Self::PrivateKey07
98    }
99
100    /// Check if a slot can store certificates.
101    pub fn is_certificate(&self) -> bool {
102        Self::Certificate09 <= *self
103    }
104
105    pub fn keys() -> KeysIter {
106        KeysIter(0x00..=0x0f)
107    }
108}
109
110pub struct KeysIter(RangeInclusive<usize>);
111
112impl Iterator for KeysIter {
113    type Item = Slot;
114    fn next(&mut self) -> Option<Self::Item> {
115        use Slot::*;
116        self.0.next().and_then(|i| match i {
117            x if x == PrivateKey00 as usize => PrivateKey00.into(),
118            x if x == PrivateKey01 as usize => PrivateKey01.into(),
119            x if x == PrivateKey02 as usize => PrivateKey02.into(),
120            x if x == PrivateKey03 as usize => PrivateKey03.into(),
121            x if x == PrivateKey04 as usize => PrivateKey04.into(),
122            x if x == PrivateKey05 as usize => PrivateKey05.into(),
123            x if x == PrivateKey06 as usize => PrivateKey06.into(),
124            x if x == PrivateKey07 as usize => PrivateKey07.into(),
125            x if x == Data08 as usize => Data08.into(),
126            x if x == Certificate09 as usize => Certificate09.into(),
127            x if x == Certificate0a as usize => Certificate0a.into(),
128            x if x == Certificate0b as usize => Certificate0b.into(),
129            x if x == Certificate0c as usize => Certificate0c.into(),
130            x if x == Certificate0d as usize => Certificate0d.into(),
131            x if x == Certificate0e as usize => Certificate0e.into(),
132            x if x == Certificate0f as usize => Certificate0f.into(),
133            _ => None,
134        })
135    }
136}
137
138pub(crate) struct CertificateRepr(RangeInclusive<usize>);
139
140impl CertificateRepr {
141    pub(crate) fn new() -> Self {
142        Self(0..=2)
143    }
144}
145
146impl Iterator for CertificateRepr {
147    type Item = &'static [Range<usize>];
148    fn next(&mut self) -> Option<Self::Item> {
149        self.0.next().and_then(|i| match i {
150            0 => from_ref(&(0x04..0x20)).into(),
151            1 => [0x00..0x04, 0x08..0x20].as_ref().into(),
152            2 => from_ref(&(0x00..0x08)).into(),
153            _ => None,
154        })
155    }
156}
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161    use crate::client::Memory;
162    use core::convert::identity;
163    use core::iter::repeat;
164    use heapless::Vec;
165    use Slot::*;
166    use Zone::*;
167
168    #[test]
169    fn locate_index() {
170        assert_eq!(
171            (0, 5, 0),
172            Zone::locate_index(Memory::<(), ()>::SLOT_CONFIG_INDEX)
173        );
174        assert_eq!(
175            (2, 6, 2),
176            Zone::locate_index(Memory::<(), ()>::CHIP_OPTIONS_INDEX)
177        );
178        assert_eq!(
179            (3, 0, 0),
180            Zone::locate_index(Memory::<(), ()>::KEY_CONFIG_INDEX)
181        );
182    }
183
184    #[test]
185    fn get_slot_addr() {
186        assert_eq!(0x0038, Data.get_slot_addr(PrivateKey07, 0).unwrap());
187        for (&addr, block) in [0x0078, 0x0178, 0x0278].iter().zip(0..=2) {
188            let result = Data.get_slot_addr(Certificate0f, block).unwrap();
189            assert_eq!(addr, result);
190        }
191    }
192
193    #[test]
194    fn get_addr() {
195        assert_eq!(0x0005, Config.get_addr(0, 5).unwrap());
196        assert_eq!(0x0016, Config.get_addr(2, 6).unwrap());
197        assert_eq!(0x0018, Config.get_addr(3, 0).unwrap());
198    }
199
200    #[test]
201    fn certificate_representation() {
202        let slot_buffer = repeat(0)
203            .take(4)
204            .chain(0x00..0x20)
205            .chain(repeat(0).take(4))
206            .chain(0x20..0x40)
207            .chain(repeat(0).take(24))
208            .collect::<Vec<u8, 96>>();
209        assert_eq!(Size::Block.len() * 3, slot_buffer.len());
210        slot_buffer
211            .chunks(Size::Block.len())
212            .zip(CertificateRepr::new())
213            .scan(0, |i, (chunk, ranges)| {
214                for range in ranges {
215                    for j in &chunk[range.clone()] {
216                        assert_eq!(i, j);
217                        *i += 1;
218                    }
219                }
220                Some(())
221            })
222            .for_each(identity)
223    }
224}