at_cryptoauth/
client.rs

1use crate::command::{Ecdh, SharedSecret};
2
3use super::clock_divider::ClockDivider;
4use super::command::{
5    self, GenKey, Info, Lock, NonceCtx, PrivWrite, PublicKey, Random, Serial, Word,
6};
7use super::datalink::I2c;
8use super::error::{Error, ErrorKind};
9use super::memory::{CertificateRepr, Size, Slot, Zone};
10use super::packet::{Packet, PacketBuilder, Response};
11use super::tngtls::TrustAndGo;
12use super::{Block, Digest, Signature};
13use core::cell::RefCell;
14use core::convert::TryInto;
15use core::convert::{identity, TryFrom};
16use core::fmt::Debug;
17use embedded_hal::blocking::delay::DelayUs;
18use embedded_hal::blocking::i2c::{Read, Write};
19use heapless::Vec;
20
21pub struct Verifier<'a, PHY, D>(RefCell<Verify<'a, PHY, D>>);
22
23impl<'a, PHY, D> From<Verify<'a, PHY, D>> for Verifier<'a, PHY, D> {
24    fn from(verify: Verify<'a, PHY, D>) -> Self {
25        Self(RefCell::new(verify))
26    }
27}
28
29impl<'a, PHY, D> signature::Verifier<Signature> for Verifier<'a, PHY, D>
30where
31    PHY: Read + Write,
32    <PHY as Read>::Error: Debug,
33    <PHY as Write>::Error: Debug,
34    D: DelayUs<u32>,
35{
36    fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), signature::Error> {
37        let digest = self
38            .0
39            .borrow_mut()
40            .atca
41            .sha()
42            .digest(msg)
43            .map_err(|_| signature::Error::new())?;
44        let key_id = self.0.borrow_mut().key_id.clone();
45        let public_key = self
46            .0
47            .borrow_mut()
48            .atca
49            .generate_pubkey(key_id)
50            .map_err(|_| signature::Error::new())?;
51        self.0
52            .borrow_mut()
53            .verify_digest(&digest, signature, &public_key)
54            .map_err(|_| signature::Error::new())
55    }
56}
57
58pub struct Signer<'a, PHY, D>(RefCell<Sign<'a, PHY, D>>);
59
60impl<'a, PHY, D> From<Sign<'a, PHY, D>> for Signer<'a, PHY, D> {
61    fn from(sign: Sign<'a, PHY, D>) -> Self {
62        Self(RefCell::new(sign))
63    }
64}
65
66impl<'a, PHY, D> signature::Signer<Signature> for Signer<'a, PHY, D>
67where
68    PHY: Read + Write,
69    <PHY as Read>::Error: Debug,
70    <PHY as Write>::Error: Debug,
71    D: DelayUs<u32>,
72{
73    fn try_sign(&self, msg: &[u8]) -> Result<Signature, signature::Error> {
74        let digest = self
75            .0
76            .borrow_mut()
77            .atca
78            .sha()
79            .digest(msg)
80            .map_err(|_| signature::Error::new())?;
81        self.0
82            .borrow_mut()
83            .sign_digest(&digest)
84            .map_err(|_| signature::Error::new())
85    }
86}
87
88pub struct AtCaClient<PHY, D> {
89    i2c: I2c<PHY, D>,
90    buffer: Vec<u8, 192>,
91    clock_divider: ClockDivider,
92}
93
94impl<PHY, D> AtCaClient<PHY, D> {
95    pub fn new(phy: PHY, delay: D) -> Self {
96        let i2c = I2c::new(phy, delay);
97        let buffer = Vec::new();
98        Self {
99            i2c,
100            buffer,
101            clock_divider: ClockDivider::Zero,
102        }
103    }
104
105    fn packet_builder(&mut self) -> PacketBuilder<'_> {
106        let capacity = self.buffer.capacity();
107        self.buffer.clear();
108        self.buffer
109            .resize(capacity, 0x00u8)
110            .unwrap_or_else(|()| unreachable!("Input length equals to the current capacity."));
111        PacketBuilder::new(&mut self.buffer)
112    }
113
114    pub fn memory(&mut self) -> Memory<'_, PHY, D> {
115        Memory { atca: self }
116    }
117
118    pub fn aes(&mut self, key_id: Slot) -> Aes<'_, PHY, D> {
119        Aes { atca: self, key_id }
120    }
121
122    pub fn sha(&mut self) -> Sha<'_, PHY, D> {
123        let remaining_bytes = Vec::new();
124        Sha {
125            atca: self,
126            remaining_bytes,
127        }
128    }
129
130    pub fn sign(&mut self, key_id: Slot) -> Sign<'_, PHY, D> {
131        Sign { atca: self, key_id }
132    }
133
134    pub fn verify(&mut self, key_id: Slot) -> Verify<'_, PHY, D> {
135        Verify { atca: self, key_id }
136    }
137}
138
139impl<PHY, D> AtCaClient<PHY, D>
140where
141    PHY: Read + Write,
142    <PHY as Read>::Error: Debug,
143    <PHY as Write>::Error: Debug,
144    D: DelayUs<u32>,
145{
146    fn execute(&mut self, packet: Packet) -> Result<Response<'_>, Error> {
147        let exec_time = self.clock_divider.execution_time(packet.opcode());
148        self.i2c.execute(&mut self.buffer, packet, exec_time)
149    }
150
151    pub fn signer(&mut self, key_id: Slot) -> Signer<'_, PHY, D> {
152        self.sign(key_id).into()
153    }
154
155    pub fn verifier(&mut self, key_id: Slot) -> Verifier<'_, PHY, D> {
156        self.verify(key_id).into()
157    }
158
159    pub fn tng(&mut self) -> Result<TrustAndGo<'_, PHY, D>, Error> {
160        self.try_into()
161    }
162
163    pub fn sleep(&mut self) -> Result<(), Error> {
164        self.i2c.sleep()
165    }
166
167    pub fn info(&mut self) -> Result<Word, Error> {
168        let packet = Info::new(self.packet_builder()).revision()?;
169        self.execute(packet)?.as_ref().try_into()
170    }
171
172    pub fn random(&mut self) -> Result<Block, Error> {
173        let packet = Random::new(self.packet_builder()).random()?;
174        self.execute(packet)?.as_ref().try_into()
175    }
176
177    // Write to device's digest message buffer.
178    pub fn write_message_digest_buffer(&mut self, msg: &Digest) -> Result<(), Error> {
179        let packet = NonceCtx::new(self.packet_builder()).message_digest_buffer(msg)?;
180        self.execute(packet).map(drop)
181    }
182
183    // Create private key and output its public key.
184    pub fn create_private_key(&mut self, key_id: Slot) -> Result<PublicKey, Error> {
185        let packet = GenKey::new(self.packet_builder()).private_key(key_id)?;
186        self.execute(packet)?.as_ref().try_into()
187    }
188
189    // Write private key.
190    pub fn write_private_key(&mut self, key_id: Slot, private_key: &Block) -> Result<(), Error> {
191        let packet =
192            PrivWrite::new(self.packet_builder()).write_private_key(key_id, private_key)?;
193        self.execute(packet).map(drop)
194    }
195
196    // Given a private key created and stored in advance, calculate its public key.
197    pub fn generate_pubkey(&mut self, key_id: Slot) -> Result<PublicKey, Error> {
198        let packet = GenKey::new(self.packet_builder()).public_key(key_id)?;
199        self.execute(packet)?.as_ref().try_into()
200    }
201
202    pub fn diffie_hellman(
203        &mut self,
204        key_id: Slot,
205        public_key: PublicKey,
206    ) -> Result<SharedSecret, Error> {
207        let packet = Ecdh::new(self.packet_builder()).diffie_hellman(key_id, public_key)?;
208        self.execute(packet)?.as_ref().try_into()
209    }
210}
211
212// Memory zones consist of config, data and OTP.
213pub struct Memory<'a, PHY, D> {
214    atca: &'a mut AtCaClient<PHY, D>,
215}
216
217impl<'a, PHY, D> Memory<'a, PHY, D> {
218    pub(crate) const SLOT_CONFIG_INDEX: usize = 20;
219    pub(crate) const CHIP_OPTIONS_INDEX: usize = 90;
220    pub(crate) const KEY_CONFIG_INDEX: usize = 96;
221}
222
223impl<'a, PHY, D> Memory<'a, PHY, D>
224where
225    PHY: Read + Write,
226    <PHY as Read>::Error: Debug,
227    <PHY as Write>::Error: Debug,
228    D: DelayUs<u32>,
229{
230    pub fn serial_number(&mut self) -> Result<Serial, Error> {
231        let packet =
232            command::Read::new(self.atca.packet_builder()).read(Zone::Config, Size::Block, 0, 0)?;
233        self.atca.execute(packet)?.as_ref().try_into()
234    }
235
236    pub fn pubkey(&mut self, key_id: Slot) -> Result<PublicKey, Error> {
237        let mut pubkey = PublicKey::default();
238        CertificateRepr::new()
239            .enumerate()
240            .scan(0, |offset, (i, ranges)| {
241                let result = command::Read::new(self.atca.packet_builder())
242                    .slot(key_id, i as u8)
243                    .and_then(|packet| {
244                        let response = self.atca.execute(packet)?;
245                        for range in ranges {
246                            let dst = *offset..*offset + range.len();
247                            pubkey.as_mut()[dst].copy_from_slice(&response.as_ref()[range.clone()]);
248                            *offset += range.len();
249                        }
250                        Ok(())
251                    });
252                Some(result)
253            })
254            .try_for_each(identity)
255            .map(|()| pubkey)
256    }
257
258    pub fn write_pubkey(&mut self, key_id: Slot, pubkey: impl AsRef<[u8]>) -> Result<(), Error> {
259        let mut data = Block::default();
260        CertificateRepr::new()
261            .enumerate()
262            .scan(0, |offset, (i, ranges)| {
263                // Initialize block sized buffer
264                data.as_mut().iter_mut().for_each(|value| *value = 0);
265
266                for range in ranges {
267                    let src = *offset..*offset + range.len();
268                    data.as_mut()[range.clone()].copy_from_slice(&pubkey.as_ref()[src]);
269                    *offset += range.len();
270                }
271
272                let result = command::Write::new(self.atca.packet_builder())
273                    .slot(key_id, i as u8, &data)
274                    .and_then(|packet| self.atca.execute(packet).map(drop));
275
276                Some(result)
277            })
278            .try_for_each(identity)
279    }
280
281    pub fn write_aes_key(&mut self, key_id: Slot, aes_key: impl AsRef<[u8]>) -> Result<(), Error> {
282        let mut data = Block::default();
283        data.as_mut()[..0x10].copy_from_slice(aes_key.as_ref());
284        let packet =
285            command::Write::new(self.atca.packet_builder()).slot(key_id, 0 as u8, &data)?;
286        self.atca.execute(packet).map(drop)
287    }
288
289    pub fn is_slot_locked(&mut self, slot: Slot) -> Result<bool, Error> {
290        let zone = Zone::Config;
291        let size = Size::Word;
292        let block = 2;
293        let word_offset = 6;
294        let packet =
295            command::Read::new(self.atca.packet_builder()).read(zone, size, block, word_offset)?;
296        let response = self.atca.execute(packet)?;
297        let word = Word::try_from(response.as_ref())?;
298        let slot_locked_bytes = word.as_ref()[..2]
299            .try_into()
300            .map(u16::from_le_bytes)
301            .unwrap_or_else(|_| unreachable!());
302        Ok(slot_locked_bytes & (0x01u16 << slot as u32) == 0x00)
303    }
304
305    pub fn is_locked(&mut self, zone: Zone) -> Result<bool, Error> {
306        let size = Size::Word;
307        let block = 2;
308        let word_offset = 5;
309        let packet = command::Read::new(self.atca.packet_builder()).read(
310            Zone::Config,
311            size,
312            block,
313            word_offset,
314        )?;
315        let response = self.atca.execute(packet)?;
316        let word = Word::try_from(response.as_ref())?;
317        match zone {
318            Zone::Config => Ok(word.as_ref()[3] != 0x55),
319            Zone::Data => Ok(word.as_ref()[2] != 0x55),
320            Zone::Otp => Err(ErrorKind::BadParam.into()),
321        }
322    }
323
324    pub fn lock_slot(&mut self, key_id: Slot) -> Result<(), Error> {
325        let packet = Lock::new(self.atca.packet_builder()).slot(key_id)?;
326        self.atca.execute(packet).map(drop)
327    }
328
329    pub fn lock(&mut self, zone: Zone) -> Result<(), Error> {
330        let packet = Lock::new(self.atca.packet_builder()).zone(zone, None)?;
331        self.atca.execute(packet).map(drop)
332    }
333
334    pub fn lock_crc(&mut self, zone: Zone, crc: u16) -> Result<(), Error> {
335        let packet = Lock::new(self.atca.packet_builder()).zone(zone, Some(crc))?;
336        self.atca.execute(packet).map(drop)
337    }
338
339    pub fn chip_options(&mut self) -> Result<u16, Error> {
340        let (block, offset, pos) = Zone::locate_index(Self::CHIP_OPTIONS_INDEX);
341        let range = pos as usize..pos as usize + 2;
342        self.read_config(Size::Word, block, offset).map(|resp| {
343            resp.as_ref()[range]
344                .try_into()
345                .map(u16::from_le_bytes)
346                .unwrap_or_else(|_| unreachable!())
347        })
348    }
349
350    pub fn permission(&mut self, slot: Slot) -> Result<u16, Error> {
351        let index = Self::SLOT_CONFIG_INDEX + (slot as usize * 2);
352        let (block, offset, pos) = Zone::locate_index(index);
353        let range = pos as usize..pos as usize + 2;
354        self.read_config(Size::Word, block, offset).map(|resp| {
355            resp.as_ref()[range]
356                .try_into()
357                .map(u16::from_le_bytes)
358                .unwrap_or_else(|_| unreachable!())
359        })
360    }
361
362    pub fn key_type(&mut self, slot: Slot) -> Result<u16, Error> {
363        let index = Self::KEY_CONFIG_INDEX + (slot as usize * 2);
364        let (block, offset, pos) = Zone::locate_index(index);
365        let range = pos as usize..pos as usize + 2;
366        self.read_config(Size::Word, block, offset).map(|resp| {
367            resp.as_ref()[range]
368                .try_into()
369                .map(u16::from_le_bytes)
370                .unwrap_or_else(|_| unreachable!())
371        })
372    }
373
374    // TODO: Testing purpose only.
375    pub fn read_config(
376        &mut self,
377        size: Size,
378        block: u8,
379        offset: u8,
380    ) -> Result<Response<'_>, Error> {
381        let packet = command::Read::new(self.atca.packet_builder()).read(
382            Zone::Config,
383            size,
384            block,
385            offset,
386        )?;
387        self.atca.execute(packet)
388    }
389
390    pub fn write_config(
391        &mut self,
392        size: Size,
393        block: u8,
394        offset: u8,
395        data: impl AsRef<[u8]>,
396    ) -> Result<(), Error> {
397        let packet = command::Write::new(self.atca.packet_builder()).write(
398            Zone::Config,
399            size,
400            block,
401            offset,
402            data,
403        )?;
404        self.atca.execute(packet).map(drop)
405    }
406}
407
408// Method signature is taken from cipher::block::BlockCipher.
409// AES
410pub struct Aes<'a, PHY, D> {
411    atca: &'a mut AtCaClient<PHY, D>,
412    key_id: Slot,
413}
414
415impl<'a, PHY, D> Aes<'a, PHY, D>
416where
417    PHY: Read + Write,
418    <PHY as Read>::Error: Debug,
419    <PHY as Write>::Error: Debug,
420    D: DelayUs<u32>,
421{
422    pub fn encrypt(&mut self, plaintext: &[u8], ciphertext: &mut [u8]) -> Result<(), Error> {
423        use command::Aes as AesCmd;
424
425        if plaintext.len() != ciphertext.len() {
426            return Err(ErrorKind::BadParam.into());
427        }
428
429        for (plain, cipher) in plaintext
430            .chunks(AesCmd::DATA_SIZE)
431            .zip(ciphertext.chunks_mut(AesCmd::DATA_SIZE))
432        {
433            // Input length should be exactly 16 bytes. Otherwise the device
434            // couldn't recognize the command properly. If the length is not
435            // enough, sufficient number of 0s are padded.
436            let packet = AesCmd::new(self.atca.packet_builder()).encrypt(self.key_id, plain)?;
437
438            // Encrypt plain bytes and write the result to cipher.
439            let response = self.atca.execute(packet)?;
440            if response.as_ref().len() != AesCmd::DATA_SIZE {
441                return Err(ErrorKind::InvalidSize.into());
442            }
443            cipher.copy_from_slice(response.as_ref());
444        }
445        Ok(())
446    }
447
448    pub fn decrypt(&mut self, ciphertext: &[u8], plaintext: &mut [u8]) -> Result<(), Error> {
449        use command::Aes as AesCmd;
450
451        if ciphertext.len() != plaintext.len() {
452            return Err(ErrorKind::BadParam.into());
453        }
454
455        for (cipher, plain) in ciphertext
456            .chunks(AesCmd::DATA_SIZE)
457            .zip(plaintext.chunks_mut(AesCmd::DATA_SIZE))
458        {
459            // Input length should be exactly 16 bytes. Otherwise the device
460            // couldn't recognize the command properly. If the length is not
461            // enough, sufficient number of 0s are padded.
462            let packet = AesCmd::new(self.atca.packet_builder()).decrypt(self.key_id, cipher)?;
463
464            // Decrypt cipher bytes and write the result to plain.
465            let response = self.atca.execute(packet)?;
466            if response.as_ref().len() != AesCmd::DATA_SIZE {
467                return Err(ErrorKind::InvalidSize.into());
468            }
469            plain.copy_from_slice(response.as_ref());
470        }
471        Ok(())
472    }
473}
474
475// SHA
476pub struct Sha<'a, PHY, D> {
477    atca: &'a mut AtCaClient<PHY, D>,
478    remaining_bytes: Vec<u8, 64>,
479}
480
481impl<'a, PHY, D> Sha<'a, PHY, D>
482where
483    PHY: Read + Write,
484    <PHY as Read>::Error: Debug,
485    <PHY as Write>::Error: Debug,
486    D: DelayUs<u32>,
487{
488    pub fn init(&mut self) -> Result<(), Error> {
489        let packet = command::Sha::new(self.atca.packet_builder()).start()?;
490        self.atca.execute(packet).map(drop)
491    }
492
493    // See digest::Update
494    pub fn update(&mut self, data: impl AsRef<[u8]>) -> Result<(), Error> {
495        let capacity = 0x40;
496        let length = data.as_ref().len();
497
498        // Store remainging bytes for later processing
499        let remainder_length = data.as_ref().len() % capacity;
500        let (bytes, remainder) = data.as_ref().split_at(length - remainder_length);
501        self.remaining_bytes.extend_from_slice(remainder).ok();
502
503        // Execute update command
504        bytes.chunks(capacity).try_for_each(|chunk| {
505            let packet = command::Sha::new(self.atca.packet_builder()).update(chunk)?;
506            self.atca.execute(packet).map(drop)
507        })
508    }
509
510    pub fn chain(&mut self, data: impl AsRef<[u8]>) -> Result<&mut Self, Error> {
511        if self.remaining_bytes.len() != 0 {
512            // TODO: Concatinate remaining bytes and input data.
513        }
514
515        self.update(data)?;
516        Ok(self)
517    }
518
519    pub fn finalize(&mut self) -> Result<Digest, Error> {
520        let packet = command::Sha::new(self.atca.packet_builder()).end(&self.remaining_bytes)?;
521        self.atca.execute(packet)?.as_ref().try_into()
522    }
523
524    pub fn digest(&mut self, data: &[u8]) -> Result<Digest, Error> {
525        self.init()?;
526        self.update(data)?;
527        self.finalize()
528    }
529}
530
531// Method signatures are taken from signature::DigestSigner.
532// Sign
533pub struct Sign<'a, PHY, D> {
534    atca: &'a mut AtCaClient<PHY, D>,
535    key_id: Slot,
536}
537
538impl<'a, PHY, D> Sign<'a, PHY, D>
539where
540    PHY: Read + Write,
541    <PHY as Read>::Error: Debug,
542    <PHY as Write>::Error: Debug,
543    D: DelayUs<u32>,
544{
545    // Takes a 32-byte message to be signed, typically the SHA256 hash of the
546    // full message.
547    pub fn sign_digest(&mut self, digest: &Digest) -> Result<Signature, Error> {
548        // 1. Random value generation
549        self.atca.random()?;
550        // 2. Nonce load
551        self.atca.write_message_digest_buffer(digest)?;
552        // 3. Sign
553        let packet = command::Sign::new(self.atca.packet_builder()).external(self.key_id)?;
554        self.atca.execute(packet)?.as_ref().try_into()
555    }
556}
557
558pub struct Verify<'a, PHY, D> {
559    atca: &'a mut AtCaClient<PHY, D>,
560    key_id: Slot,
561}
562
563impl<'a, PHY, D> Verify<'a, PHY, D>
564where
565    PHY: Read + Write,
566    <PHY as Read>::Error: Debug,
567    <PHY as Write>::Error: Debug,
568    D: DelayUs<u32>,
569{
570    // Takes a 32-byte message to be signed, typically the SHA256 hash of the
571    // full message and signature.
572    pub fn verify_digest(
573        &mut self,
574        digest: &Digest,
575        signature: &Signature,
576        public_key: &PublicKey,
577    ) -> Result<(), Error> {
578        // 1. Nonce load
579        self.atca.write_message_digest_buffer(digest)?;
580        // 2. Verify
581        let packet =
582            command::Verify::new(self.atca.packet_builder()).external(signature, public_key)?;
583        self.atca.execute(packet).map(drop)
584    }
585}