ecc608_linux/
ecc.rs

1use crate::{
2    constants::ATCA_CMD_SIZE_MAX,
3    transport,
4    {
5        command::{EccCommand, EccResponse},
6        Address, DataBuffer, Error, KeyConfig, Result, SlotConfig, Zone,
7    },
8};
9use bytes::{BufMut, Bytes, BytesMut};
10use sha2::{Digest, Sha256};
11use std::time::Duration;
12
13pub use crate::command::KeyType;
14
15pub struct Ecc {
16    transport: transport::TransportProtocol,
17    config: EccConfig,
18}
19
20pub const MAX_SLOT: u8 = 15;
21
22pub(crate) const CMD_RETRIES: u8 = 10;
23
24#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
25pub struct EccConfig {
26    pub wake_delay: u32,
27    pub durations: EccCommandDuration,
28}
29
30#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
31pub struct EccCommandDuration {
32    pub info: u32,
33    pub read: u32,
34    pub write: u32,
35    pub lock: u32,
36    pub nonce: u32,
37    pub random: u32,
38    pub genkey: u32,
39    pub sign: u32,
40    pub ecdh: u32,
41}
42
43impl EccConfig {
44    pub fn from_path(path: &str) -> Result<Self> {
45        if path.starts_with("/dev/tty") {
46            Ok(Self::for_swi())
47        } else if path.starts_with("/dev/i2c") {
48            Ok(Self::for_i2c())
49        } else {
50            Err(Error::invalid_address())
51        }
52    }
53
54    pub fn for_swi() -> Self {
55        Self {
56            wake_delay: 1500,
57            durations: EccCommandDuration {
58                info: 500,
59                read: 800,
60                write: 8_000,
61                lock: 19_500,
62                nonce: 17_000,
63                random: 15_000,
64                genkey: 85_000,
65                sign: 80_000,
66                ecdh: 42_000,
67            },
68        }
69    }
70
71    pub fn for_i2c() -> Self {
72        Self {
73            wake_delay: 1000,
74            durations: EccCommandDuration {
75                info: 500,
76                read: 800,
77                write: 8_000,
78                lock: 19_500,
79                nonce: 7_000,
80                random: 15_000,
81                genkey: 59_000,
82                sign: 62_000,
83                ecdh: 28_000,
84            },
85        }
86    }
87
88    pub fn command_duration(&self, command: &EccCommand) -> Duration {
89        let micros = match command {
90            EccCommand::Info => self.durations.info,
91            EccCommand::Read { .. } => self.durations.read,
92            EccCommand::Write { .. } => self.durations.write,
93            EccCommand::Lock { .. } => self.durations.lock,
94            EccCommand::Nonce { .. } => self.durations.nonce,
95            EccCommand::Random => self.durations.random,
96            EccCommand::GenKey { .. } => self.durations.genkey,
97            EccCommand::Sign { .. } => self.durations.sign,
98            EccCommand::Ecdh { .. } => self.durations.ecdh,
99        };
100        Duration::from_micros(micros as u64)
101    }
102}
103
104impl Ecc {
105    pub fn from_path(path: &str, address: u16, config: Option<EccConfig>) -> Result<Self> {
106        let transport = if path.starts_with("/dev/tty") {
107            transport::SwiTransport::new(path)?.into()
108        } else if path.starts_with("/dev/i2c") {
109            transport::I2cTransport::new(path, address)?.into()
110        } else {
111            return Err(Error::invalid_address());
112        };
113
114        let config = if let Some(config) = config {
115            config
116        } else {
117            EccConfig::from_path(path)?
118        };
119
120        Ok(Self { transport, config })
121    }
122
123    pub fn get_info(&mut self) -> Result<Bytes> {
124        self.send_command(&EccCommand::info())
125    }
126
127    /// Returns the 9 bytes that represent the serial number of the ECC. Per
128    /// section 2.2.6 of the Data Sheet the first two, and last byte of the
129    /// returned binary will always be `[0x01, 0x23]` and `0xEE`
130    pub fn get_serial(&mut self) -> Result<Bytes> {
131        let bytes = self.read(true, Address::config(0, 0)?)?;
132        let mut result = BytesMut::with_capacity(9);
133        result.extend_from_slice(&bytes.slice(0..=3));
134        result.extend_from_slice(&bytes.slice(8..=12));
135        Ok(result.freeze())
136    }
137
138    pub fn genkey(&mut self, key_type: KeyType, slot: u8) -> Result<Bytes> {
139        self.send_command(&EccCommand::genkey(key_type, slot))
140    }
141
142    pub fn get_slot_config(&mut self, slot: u8) -> Result<SlotConfig> {
143        let bytes = self.read(false, Address::slot_config(slot)?)?;
144        let (s0, s1) = bytes.split_at(2);
145        match slot & 1 == 0 {
146            true => Ok(SlotConfig::from(s0)),
147            false => Ok(SlotConfig::from(s1)),
148        }
149    }
150
151    pub fn set_slot_config(&mut self, slot: u8, config: &SlotConfig) -> Result {
152        let slot_address = Address::slot_config(slot)?;
153        let bytes = self.read(false, slot_address)?;
154        let (s0, s1) = bytes.split_at(2);
155        let mut new_bytes = BytesMut::with_capacity(4);
156        match slot & 1 == 0 {
157            true => {
158                new_bytes.put_u16(config.into());
159                new_bytes.extend_from_slice(s1);
160            }
161            false => {
162                new_bytes.extend_from_slice(s0);
163                new_bytes.put_u16(config.into());
164            }
165        }
166        self.write(slot_address, &new_bytes.freeze())
167    }
168
169    pub fn get_key_config(&mut self, slot: u8) -> Result<KeyConfig> {
170        let bytes = self.read(false, Address::key_config(slot)?)?;
171        let (s0, s1) = bytes.split_at(2);
172        match slot & 1 == 0 {
173            true => Ok(KeyConfig::from(s0)),
174            false => Ok(KeyConfig::from(s1)),
175        }
176    }
177
178    pub fn set_key_config(&mut self, slot: u8, config: &KeyConfig) -> Result {
179        let slot_address = Address::key_config(slot)?;
180        let bytes = self.read(false, slot_address)?;
181        let (s0, s1) = bytes.split_at(2);
182        let mut new_bytes = BytesMut::with_capacity(4);
183        match slot & 1 == 0 {
184            true => {
185                new_bytes.put_u16(config.into());
186                new_bytes.extend_from_slice(s1);
187            }
188            false => {
189                new_bytes.extend_from_slice(s0);
190                new_bytes.put_u16(config.into());
191            }
192        }
193        self.write(slot_address, &new_bytes.freeze())
194    }
195
196    pub fn get_locked(&mut self, zone: &Zone) -> Result<bool> {
197        let bytes = self.read(false, Address::config(2, 5)?)?;
198        let (_, s1) = bytes.split_at(2);
199        match zone {
200            Zone::Config => Ok(s1[1] == 0),
201            Zone::Data => Ok(s1[0] == 0),
202        }
203    }
204
205    pub fn set_locked(&mut self, zone: Zone) -> Result {
206        self.send_command(&EccCommand::lock(zone)).map(|_| ())
207    }
208
209    pub fn sign(&mut self, key_slot: u8, data: &[u8]) -> Result<Bytes> {
210        let digest = Sha256::digest(data);
211        let _ = self.send_command_retries(
212            &EccCommand::nonce(DataBuffer::MessageDigest, Bytes::copy_from_slice(&digest)),
213            true,
214            false,
215            1,
216        )?;
217        self.send_command_retries(
218            &EccCommand::sign(DataBuffer::MessageDigest, key_slot),
219            false,
220            true,
221            1,
222        )
223    }
224
225    pub fn ecdh(&mut self, key_slot: u8, x: &[u8], y: &[u8]) -> Result<Bytes> {
226        self.send_command(&EccCommand::ecdh(
227            Bytes::copy_from_slice(x),
228            Bytes::copy_from_slice(y),
229            key_slot,
230        ))
231    }
232
233    pub fn random(&mut self) -> Result<Bytes> {
234        self.send_command(&EccCommand::random())
235    }
236
237    pub fn nonce(&mut self, target: DataBuffer, data: &[u8]) -> Result {
238        self.send_command(&EccCommand::nonce(target, Bytes::copy_from_slice(data)))
239            .map(|_| ())
240    }
241
242    pub fn read(&mut self, read_32: bool, address: Address) -> Result<Bytes> {
243        self.send_command(&EccCommand::read(read_32, address))
244    }
245
246    pub fn write(&mut self, address: Address, bytes: &[u8]) -> Result {
247        self.send_command(&EccCommand::write(address, bytes))
248            .map(|_| ())
249    }
250
251    pub(crate) fn send_command(&mut self, command: &EccCommand) -> Result<Bytes> {
252        self.send_command_retries(command, true, true, CMD_RETRIES)
253    }
254
255    pub(crate) fn send_command_retries(
256        &mut self,
257        command: &EccCommand,
258        wake: bool,
259        idle: bool,
260        retries: u8,
261    ) -> Result<Bytes> {
262        let mut buf = BytesMut::with_capacity(ATCA_CMD_SIZE_MAX as usize);
263        let delay = self.config.command_duration(command);
264        let wake_delay = Duration::from_micros(self.config.wake_delay as u64);
265
266        for retry in 0..retries {
267            buf.clear();
268            buf.put_u8(self.transport.put_command_flag());
269            command.bytes_into(&mut buf);
270
271            if wake {
272                self.transport.send_wake(wake_delay)?;
273            }
274
275            if let Err(_err) = self.transport.send_recv_buf(delay, &mut buf) {
276                continue;
277            }
278
279            let response = EccResponse::from_bytes(&buf[..])?;
280            match response {
281                EccResponse::Data(bytes) => {
282                    if idle {
283                        self.transport.send_idle();
284                    }
285                    return Ok(bytes);
286                }
287                EccResponse::Error(err) if err.is_recoverable() && retry < retries => continue,
288                EccResponse::Error(err) => {
289                    self.transport.send_sleep();
290                    return Err(Error::ecc(err));
291                }
292            }
293        }
294        self.transport.send_sleep();
295        Err(Error::timeout())
296    }
297}