at_cryptoauth/
tngtls.rs

1// Pre-configured device memory state and pre-provisioned key store access
2// management. 1. Fully specified configuration zone. 2. One permanent primary
3// P-256 Elliptic Curve Cryptography (ECC) private key fixed at the first object
4// creation. 3. One internal sign private key for key attestation. 4. Three
5// secondary P-256 ECC private keys that can be regenerated by the user. 5.
6// Signer public key from signer certificate. 6. ECDH/KDF key slot capable of
7// being used with AES keys and commands. 7. X.509 Compressed Certificate
8// Storage.
9use super::client::{AtCaClient, Memory, Sha};
10use super::error::Error;
11use super::memory::{Size, Slot, Zone};
12use core::convert::TryFrom;
13use core::fmt::Debug;
14use digest::{FixedOutputDirty, Reset, Update};
15use embedded_hal::blocking::delay::DelayUs;
16use embedded_hal::blocking::i2c::{Read, Write};
17use generic_array::typenum::U32;
18use generic_array::GenericArray;
19
20pub const AUTH_PRIVATE_KEY: Slot = Slot::PrivateKey00;
21pub const SIGN_PRIVATE_KEY: Slot = Slot::PrivateKey01;
22pub const USER_PRIVATE_KEY1: Slot = Slot::PrivateKey02;
23pub const USER_PRIVATE_KEY2: Slot = Slot::PrivateKey03;
24pub const USER_PRIVATE_KEY3: Slot = Slot::PrivateKey04;
25pub const IO_PROTECTION_KEY: Slot = Slot::PrivateKey06;
26pub const AES_KEY: Slot = Slot::Certificate09;
27pub const DEVICE_CERTIFICATE: Slot = Slot::Certificate0a;
28pub const SIGNER_PUBLIC_KEY: Slot = Slot::Certificate0b;
29pub const SIGNER_CERTIFICATE: Slot = Slot::Certificate0c;
30
31pub struct Hasher<'a, PHY, D>(Sha<'a, PHY, D>);
32impl<'a, PHY, D> From<Sha<'a, PHY, D>> for Hasher<'a, PHY, D> {
33    fn from(sha: Sha<'a, PHY, D>) -> Self {
34        Self(sha)
35    }
36}
37
38impl<'a, PHY, D> Clone for Hasher<'a, PHY, D> {
39    fn clone(&self) -> Self {
40        unimplemented!()
41    }
42}
43
44impl<'a, PHY, D> Default for Hasher<'a, PHY, D> {
45    fn default() -> Self {
46        unimplemented!()
47    }
48}
49
50impl<'a, PHY, D> Update for Hasher<'a, PHY, D>
51where
52    PHY: Read + Write,
53    <PHY as Read>::Error: Debug,
54    <PHY as Write>::Error: Debug,
55    D: DelayUs<u32>,
56{
57    fn update(&mut self, data: impl AsRef<[u8]>) {
58        self.0.update(data).expect("update operation failed");
59    }
60}
61
62impl<'a, PHY, D> FixedOutputDirty for Hasher<'a, PHY, D>
63where
64    PHY: Read + Write,
65    <PHY as Read>::Error: Debug,
66    <PHY as Write>::Error: Debug,
67    D: DelayUs<u32>,
68{
69    type OutputSize = U32;
70    fn finalize_into_dirty(&mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
71        let digest = self.0.finalize().expect("finalize operation failed");
72        out.as_mut_slice().copy_from_slice(digest.as_ref());
73    }
74}
75
76impl<'a, PHY, D> Reset for Hasher<'a, PHY, D>
77where
78    PHY: Read + Write,
79    <PHY as Read>::Error: Debug,
80    <PHY as Write>::Error: Debug,
81    D: DelayUs<u32>,
82{
83    fn reset(&mut self) {}
84}
85
86pub struct TrustAndGo<'a, PHY, D> {
87    atca: &'a mut AtCaClient<PHY, D>,
88}
89
90impl<'a, PHY, D> TrustAndGo<'a, PHY, D> {
91    // Miscellaneous device states.
92    const TNG_TLS_SLOT_CONFIG_DATA: [u8; Size::Block as usize] = [
93        // Index 20..=51, block = 0, offset = 5
94        0x85, 0x00, // Slot 0x00, Primary private key
95        0x82, 0x00, // Slot 0x01, Internal sign private key
96        0x85, 0x20, 0x85, 0x20, 0x85, 0x20, // Slot 02, 03 and 04, Secondary private keys 1-3
97        0x8f, 0x8f, // Slot 0x05, reserved.
98        0x8f, 0x0f, // Slot 0x06, I/O protection key
99        0xaf, 0x8f, // Slot 0x07, reserved.
100        0x0f, 0x0f, // Slot 0x08, General data
101        0x8f, 0x0f, // Slot 0x09, AES key
102        0x0f, 0x8f, // Slot 0x0a, Device compressed certificate
103        0x0f, 0x8f, // Slot 0x0b, Signer public key
104        0x0f, 0x8f, // Slot 0x0c, Signer compressed certificate
105        0x00, 0x00, 0x00, 0x00, 0xaf, 0x8f, // Slot 0x0d, 0x0e and 0x0f, reserved.
106    ];
107
108    const TNG_TLS_CHIP_OPTIONS: [u8; Size::Word as usize] = [
109        // Index 88..=91, block = 2, offset = 6
110        0xff, 0xff, 0x60, 0x0e,
111    ];
112
113    const TNG_TLS_KEY_CONFIG_DATA: [u8; Size::Block as usize] = [
114        // Index 96..=127, block = 3, offset = 0
115        0x53, 0x00, // 0x00
116        0x53, 0x00, // 0x01
117        0x73, 0x00, 0x73, 0x00, 0x73, 0x00, // 02, 03 and 04
118        0x1c, 0x00, // 0x05, reserved.
119        0x7c, 0x00, // 0x06
120        0x3c, 0x00, // 0x07, reserved.
121        0x3c, 0x00, // 0x08
122        0x1a, 0x00, // 0x09
123        0x1c, 0x00, // 0x0a
124        0x10, 0x00, // 0x0b
125        0x1c, 0x00, // 0x0c
126        0x3c, 0x00, 0x3c, 0x00, 0x1c, 0x00, // 0x0d, 0x0e and 0x0f, reserved.
127    ];
128}
129
130// Methods for preparing device state. Configuraion, random nonce and key creation and so on.
131impl<'a, PHY, D> TrustAndGo<'a, PHY, D>
132where
133    PHY: Read + Write,
134    <PHY as Read>::Error: Debug,
135    <PHY as Write>::Error: Debug,
136    D: DelayUs<u32>,
137{
138    // Slot config
139    pub fn configure_permissions(&mut self) -> Result<(), Error> {
140        Self::TNG_TLS_SLOT_CONFIG_DATA
141            .chunks(Size::Word.len())
142            .enumerate()
143            .try_for_each(|(i, word)| {
144                let index = Memory::<PHY, D>::SLOT_CONFIG_INDEX + i * Size::Word.len();
145                let (block, offset, _) = Zone::locate_index(index);
146                self.atca
147                    .memory()
148                    .write_config(Size::Word, block, offset, word)
149                    .map(drop)
150            })
151    }
152
153    // Chip options
154    pub fn configure_chip_options(&mut self) -> Result<(), Error> {
155        let (block, offset, _) = Zone::locate_index(Memory::<PHY, D>::CHIP_OPTIONS_INDEX);
156        self.atca
157            .memory()
158            .write_config(Size::Word, block, offset, &Self::TNG_TLS_CHIP_OPTIONS)
159    }
160
161    // Key config
162    pub fn configure_key_types(&mut self) -> Result<(), Error> {
163        let (block, offset, _) = Zone::locate_index(Memory::<PHY, D>::KEY_CONFIG_INDEX);
164        self.atca
165            .memory()
166            .write_config(Size::Block, block, offset, &Self::TNG_TLS_KEY_CONFIG_DATA)
167    }
168}
169
170// On creation of TNG object, enforce stateful configuration.
171impl<'a, PHY, D> TryFrom<&'a mut AtCaClient<PHY, D>> for TrustAndGo<'a, PHY, D>
172where
173    PHY: Read + Write,
174    <PHY as Read>::Error: Debug,
175    <PHY as Write>::Error: Debug,
176    D: DelayUs<u32>,
177{
178    type Error = Error;
179    fn try_from(atca: &'a mut AtCaClient<PHY, D>) -> Result<Self, Self::Error> {
180        let mut tng = Self { atca };
181        // Check if configuration zone is locked.
182        if !tng.atca.memory().is_locked(Zone::Config)? {
183            tng.configure_permissions()?;
184            tng.configure_chip_options()?;
185            tng.configure_key_types()?;
186            // Lock config zone
187            tng.atca.memory().lock(Zone::Config)?;
188        }
189
190        // Check if data zone is locked.
191        if !tng.atca.memory().is_locked(Zone::Data)? {
192            // Only lock the data zone for release build
193            #[cfg(not(debug_assertions))]
194            tng.atca.memory().lock(Zone::Data)?;
195        }
196
197        Ok(tng)
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204    use crate::command::OpCode;
205    use core::convert::TryInto;
206    use core::ops::Deref;
207    use heapless::Vec;
208    use OpCode::*;
209    const KEY_TYPE_P256: u16 = 0x04; // P256 NIST ECC key
210    const KEY_TYPE_AES: u16 = 0x06; // AES-128 Key
211    const KEY_TYPE_SHA: u16 = 0x07; // SHA key or other data
212
213    struct Provision {
214        key_id: Slot,
215        permission: u16,
216        key_config: u16,
217    }
218
219    impl Provision {
220        fn new(key_id: Slot) -> Self {
221            let permission = permission(key_id);
222            let key_config = key_config(key_id);
223            Self {
224                key_id,
225                permission,
226                key_config,
227            }
228        }
229
230        fn is_private(&self) -> bool {
231            self.key_config & 0x01 != 0x00
232        }
233
234        fn key_type(&self) -> u16 {
235            (self.key_config >> 2) & 0x07
236        }
237
238        fn read_key(&self) -> u16 {
239            self.permission & 0x0f
240        }
241
242        fn encrypt_read(&self) -> bool {
243            (self.permission >> 6) & 0x01 != 0x00
244        }
245
246        fn is_secret(&self) -> bool {
247            (self.permission >> 7) & 0x01 != 0x00
248        }
249
250        fn write_config(&self) -> u16 {
251            (self.permission >> 12) & 0x0f
252        }
253
254        fn read_permission(&self) -> &str {
255            match (self.is_secret(), self.encrypt_read()) {
256                (false, false) => "Clear text",
257                (true, false) => "Never",
258                (true, true) => "Encrypted",
259                _ => panic!("Prohibited"),
260            }
261        }
262
263        fn write_permission(&self) -> &str {
264            match self.write_config() {
265                0x00 => "Clear text",
266                0x01 => "PubInvalid",
267                x if (x >> 1) == 0x01 => "Never",
268                x if (x >> 2) == 0x02 => "Never",
269                x if (x >> 2) & 0x01 == 0x01 => "Encrypted",
270                _ => panic!("Prohibited"),
271            }
272        }
273
274        // Random nonce
275        fn require_nonce(&self) -> bool {
276            (self.key_config >> 6) & 0x01 != 0x00
277        }
278
279        // Commands that returns its output to the slot.
280        fn creation_commands(&self) -> Vec<OpCode, 5> {
281            let mut commands = Vec::<OpCode, 5>::new();
282            if self.key_id.is_private_key() && self.key_type() == KEY_TYPE_P256 && self.is_secret()
283            {
284                if (self.write_config() >> 1) & 0x01 == 0x01 {
285                    commands.push(GenKey).unwrap();
286                    commands.push(DeriveKey).unwrap();
287                }
288                if (self.write_config() >> 2) & 0x01 == 0x01 {
289                    commands.push(PrivWrite).unwrap();
290                }
291            }
292            commands
293        }
294
295        // Commands that takes the slot as an intput.
296        #[allow(dead_code)]
297        fn operation_commands(&self) -> &[OpCode] {
298            let mut commands = Vec::<OpCode, 5>::new();
299            if self.key_id.is_private_key() {
300                if (self.read_key() >> 2) & 0x01 == 0x01 {
301                    commands.push(Ecdh).unwrap();
302                }
303                if self.is_secret() && self.key_type() == KEY_TYPE_P256 {
304                    commands.push(Sign).unwrap();
305                }
306                unimplemented!()
307            } else {
308                unimplemented!()
309            }
310        }
311    }
312
313    fn permission(key_id: Slot) -> u16 {
314        let data = &TrustAndGo::<(), ()>::TNG_TLS_SLOT_CONFIG_DATA;
315        let index = key_id as usize * 2;
316        let range = index..index + 2;
317        data[range]
318            .try_into()
319            .map(u16::from_le_bytes)
320            .unwrap_or_else(|_| unreachable!())
321    }
322
323    fn key_config(key_id: Slot) -> u16 {
324        let data = &TrustAndGo::<(), ()>::TNG_TLS_KEY_CONFIG_DATA;
325        let index = key_id as usize * 2;
326        let range = index..index + 2;
327        data[range]
328            .try_into()
329            .map(u16::from_le_bytes)
330            .unwrap_or_else(|_| unreachable!())
331    }
332
333    // ECC private keys can never be written with the Write and/or DeriveKey
334    // commands. Instead, GenKey and PrivWrite can be used to modify these
335    // slots.
336    #[test]
337    fn provision() {
338        let auth_priv = Provision::new(AUTH_PRIVATE_KEY);
339        assert_eq!(true, auth_priv.is_private());
340        assert_eq!(KEY_TYPE_P256, auth_priv.key_type());
341        assert_eq!(true, auth_priv.require_nonce());
342        assert_eq!(0x05, auth_priv.read_key());
343        assert_eq!("Clear text", auth_priv.write_permission());
344        assert_eq!(0, auth_priv.creation_commands().len());
345
346        let sign_priv = Provision::new(SIGN_PRIVATE_KEY);
347        assert_eq!(true, sign_priv.is_private());
348        assert_eq!(KEY_TYPE_P256, sign_priv.key_type());
349        assert_eq!(true, sign_priv.require_nonce());
350        assert_eq!(0x02, sign_priv.read_key());
351        assert_eq!("Clear text", sign_priv.write_permission());
352        assert_eq!(0, sign_priv.creation_commands().len());
353
354        for key_id in [USER_PRIVATE_KEY1, USER_PRIVATE_KEY2, USER_PRIVATE_KEY3].iter() {
355            let user_priv = Provision::new(*key_id);
356            assert_eq!(true, user_priv.is_private());
357            assert_eq!(KEY_TYPE_P256, user_priv.key_type());
358            assert_eq!(true, user_priv.require_nonce());
359            assert_eq!(0x05, user_priv.read_key());
360            assert_eq!("Never", user_priv.write_permission());
361            assert_eq!(&[GenKey, DeriveKey], user_priv.creation_commands().deref());
362        }
363
364        let io_protect = Provision::new(IO_PROTECTION_KEY);
365        assert_eq!(KEY_TYPE_SHA, io_protect.key_type());
366        assert_eq!("Clear text", io_protect.write_permission());
367        assert_eq!(true, io_protect.require_nonce());
368        assert_eq!(0, io_protect.creation_commands().len());
369
370        let aes_key = Provision::new(AES_KEY);
371        assert_eq!(KEY_TYPE_AES, aes_key.key_type());
372        assert_eq!("Never", aes_key.read_permission());
373        assert_eq!("Clear text", aes_key.write_permission());
374        assert_eq!(0x00, aes_key.write_config());
375
376        let device_cert = Provision::new(DEVICE_CERTIFICATE);
377        assert_eq!(KEY_TYPE_SHA, device_cert.key_type());
378        assert_eq!("Clear text", device_cert.read_permission());
379        assert_eq!("Never", device_cert.write_permission());
380        assert_eq!(0x08, device_cert.write_config());
381
382        let signer_pub = Provision::new(SIGNER_PUBLIC_KEY);
383        assert_eq!(KEY_TYPE_P256, signer_pub.key_type());
384        assert_eq!("Clear text", signer_pub.read_permission());
385        assert_eq!("Never", signer_pub.write_permission());
386        assert_eq!(0x08, signer_pub.write_config());
387
388        let signer_cert = Provision::new(SIGNER_CERTIFICATE);
389        assert_eq!(KEY_TYPE_SHA, signer_cert.key_type());
390        assert_eq!("Clear text", signer_cert.read_permission());
391        assert_eq!("Never", signer_cert.write_permission());
392        assert_eq!(0x08, signer_cert.write_config());
393    }
394}