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 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}