1use crate::{
2 constants::{
3 ATCA_ECDH, ATCA_GENKEY, ATCA_INFO, ATCA_LOCK, ATCA_NONCE, ATCA_RANDOM, ATCA_READ,
4 ATCA_RSP_SIZE_MIN, ATCA_SIGN, ATCA_WRITE, CMD_STATUS_BYTE_COMM, CMD_STATUS_BYTE_ECC,
5 CMD_STATUS_BYTE_EXEC, CMD_STATUS_BYTE_PARSE, CMD_STATUS_BYTE_SELF_TEST,
6 CMD_STATUS_BYTE_SUCCESS, CMD_STATUS_BYTE_WATCHDOG,
7 },
8 Address, DataBuffer, Result, Zone,
9};
10use bitfield::bitfield;
11use bytes::{Buf, BufMut, Bytes, BytesMut};
12
13#[derive(Debug, PartialEq, Eq)]
14pub enum KeyType {
15 Public,
16 Private,
17}
18
19impl From<&KeyType> for u8 {
20 fn from(k: &KeyType) -> Self {
21 match k {
22 KeyType::Public => 0x00,
23 KeyType::Private => 0x04,
24 }
25 }
26}
27
28#[derive(Debug, PartialEq, Eq)]
29pub enum EccCommand {
30 Info,
31 GenKey { key_type: KeyType, slot: u8 },
32 Read { is_32: bool, address: Address },
33 Write { address: Address, data: Bytes },
34 Lock { zone: Zone },
35 Random,
36 Nonce { target: DataBuffer, data: Bytes },
37 Sign { source: DataBuffer, key_slot: u8 },
38 Ecdh { x: Bytes, y: Bytes, key_slot: u8 },
39}
40
41bitfield! {
42 #[derive(PartialEq)]
43 struct ReadWriteParam(u8);
44 impl Debug;
45 is_32, set_is_32: 7;
46 address_zone, set_address_zone: 1, 0;
47}
48
49impl From<ReadWriteParam> for u8 {
50 fn from(v: ReadWriteParam) -> Self {
51 v.0
52 }
53}
54
55bitfield! {
56 #[derive(PartialEq)]
57 struct NonceParam(u8);
58 impl Debug;
59 u8, target, set_target: 7, 6;
60 is_64, set_is_64: 5;
61 u8, mode, set_mode: 1, 0;
62}
63
64impl From<NonceParam> for u8 {
65 fn from(v: NonceParam) -> Self {
66 v.0
67 }
68}
69
70bitfield! {
71 #[derive(PartialEq)]
72 struct SignParam(u8);
73 impl Debug;
74 external, set_external: 7;
75 u8, source, set_source: 5, 5;
76}
77
78impl From<SignParam> for u8 {
79 fn from(v: SignParam) -> Self {
80 v.0
81 }
82}
83
84bitfield! {
85 #[derive(PartialEq, Eq)]
86 pub struct LockParam(u8);
87 impl Debug;
88 u8, zone, set_zone: 1, 0;
89 u8, slot, set_slot: 5, 2;
90 crc, set_crc: 7;
91}
92
93impl From<LockParam> for u8 {
94 fn from(v: LockParam) -> Self {
95 v.0
96 }
97}
98
99#[derive(Debug, PartialEq, Eq)]
100pub enum EccError {
101 ParseError,
106 Fault,
110 SelfTestError,
113 ExecError,
117 CommsError,
121 WatchDogError,
125 CrcError,
127 Unknown(u8),
129}
130
131#[derive(Debug, PartialEq, Eq)]
132pub enum EccResponse {
133 Error(EccError),
134 Data(Bytes),
135}
136
137macro_rules! put_cmd {
138 ($dest:ident, $cmd:ident, $param1:expr, $param2:expr) => {
139 $dest.put_u8($cmd);
140 $dest.put_u8($param1);
141 $dest.put_u16($param2);
142 };
143}
144
145impl EccCommand {
146 pub fn info() -> Self {
147 Self::Info
148 }
149
150 pub fn genkey(key_type: KeyType, slot: u8) -> Self {
151 Self::GenKey { key_type, slot }
152 }
153
154 pub fn read(is_32: bool, address: Address) -> Self {
155 Self::Read { is_32, address }
156 }
157
158 pub fn write(address: Address, data: &[u8]) -> Self {
159 Self::Write {
160 address,
161 data: Bytes::copy_from_slice(data),
162 }
163 }
164
165 pub fn lock(zone: Zone) -> Self {
166 Self::Lock { zone }
167 }
168
169 pub fn random() -> Self {
170 Self::Random
171 }
172
173 pub fn nonce(target: DataBuffer, data: Bytes) -> Self {
174 Self::Nonce { target, data }
175 }
176
177 pub fn sign(source: DataBuffer, key_slot: u8) -> Self {
178 Self::Sign { source, key_slot }
179 }
180
181 pub fn ecdh(x: Bytes, y: Bytes, key_slot: u8) -> Self {
182 Self::Ecdh { key_slot, x, y }
183 }
184
185 pub fn bytes_into(&self, bytes: &mut BytesMut) {
186 bytes.put_u8(0x00);
187 match self {
188 Self::Info => {
189 put_cmd!(bytes, ATCA_INFO, 0, 0);
190 }
191 Self::GenKey { key_type, slot } => {
192 put_cmd!(bytes, ATCA_GENKEY, u8::from(key_type), (*slot as u16) << 8);
193 }
194 Self::Read { is_32, address } => {
195 let mut param1 = ReadWriteParam(0);
196 param1.set_is_32(*is_32);
197 param1.set_address_zone(address.zone());
198 put_cmd!(bytes, ATCA_READ, u8::from(param1), u16::from(address));
199 }
200 Self::Write { address, data } => {
201 let mut param1 = ReadWriteParam(0);
202 param1.set_is_32(data.len() == 32);
203 param1.set_address_zone(address.zone());
204 put_cmd!(bytes, ATCA_WRITE, u8::from(param1), u16::from(address));
205 bytes.extend_from_slice(data);
206 }
207 Self::Lock { zone } => {
208 let mut param1 = LockParam(0);
209 param1.set_crc(true);
210 param1.set_zone(match zone {
211 Zone::Config => 0x00,
212 Zone::Data => 0x01,
213 });
214 put_cmd!(bytes, ATCA_LOCK, u8::from(param1), 0);
215 }
216 Self::Random => {
217 put_cmd!(bytes, ATCA_RANDOM, 0, 0);
218 }
219 Self::Nonce { target, data } => {
220 let mut param1 = NonceParam(0);
221 param1.set_mode(0x03); param1.set_target(target.into());
223 param1.set_is_64(data.len() == 64);
224 put_cmd!(bytes, ATCA_NONCE, u8::from(param1), 0);
225 bytes.extend_from_slice(data)
226 }
227 Self::Sign { source, key_slot } => {
228 let mut param1 = SignParam(0);
229 param1.set_source(source.into());
230 param1.set_external(true);
231 put_cmd!(bytes, ATCA_SIGN, u8::from(param1), (*key_slot as u16) << 8);
232 }
233 Self::Ecdh { x, y, key_slot } => {
234 put_cmd!(bytes, ATCA_ECDH, 0, (*key_slot as u16) << 8);
235 bytes.extend_from_slice(x);
236 bytes.extend_from_slice(y)
237 }
238 }
239 bytes[1] = (bytes.len() + 1) as u8;
240 bytes.put_u16_le(crc(&bytes[1..]))
241 }
242}
243
244impl EccResponse {
245 pub fn from_bytes(buf: &[u8]) -> Result<Self> {
246 const RSM: u8 = ATCA_RSP_SIZE_MIN;
247 let resp = match buf {
248 [RSM, CMD_STATUS_BYTE_SUCCESS, ..] => Self::Data(Bytes::new()),
249 [RSM, CMD_STATUS_BYTE_PARSE, ..] => Self::Error(EccError::ParseError),
250 [RSM, CMD_STATUS_BYTE_ECC, ..] => Self::Error(EccError::Fault),
251 [RSM, CMD_STATUS_BYTE_SELF_TEST, ..] => Self::Error(EccError::SelfTestError),
252 [RSM, CMD_STATUS_BYTE_EXEC, ..] => Self::Error(EccError::ExecError),
253 [RSM, CMD_STATUS_BYTE_COMM, ..] => Self::Error(EccError::CommsError),
254 [RSM, CMD_STATUS_BYTE_WATCHDOG, ..] => Self::Error(EccError::WatchDogError),
255 [RSM, error, ..] => Self::Error(EccError::Unknown(*error)),
256 _ => {
257 let (buf, mut buf_crc) = buf.split_at(buf.len() - 2);
258 let expected = crc(buf);
259 let actual = buf_crc.get_u16_le();
260 if expected != actual {
261 Self::Error(EccError::CrcError)
262 } else {
263 Self::Data(Bytes::copy_from_slice(&buf[1..]))
264 }
265 }
266 };
267 Ok(resp)
268 }
269}
270
271impl EccError {
272 pub fn is_recoverable(&self) -> bool {
273 !matches!(self, Self::ParseError | Self::ExecError)
274 }
275}
276
277fn crc(src: &[u8]) -> u16 {
278 const POLYNOM: u16 = 0x8005;
279 let mut crc: u16 = 0x0000;
280 let mut data_bit;
281 let mut crc_bit;
282 for d in src {
283 for b in 0..8 {
284 if (d & 1 << b) == 0 {
285 data_bit = 0;
286 } else {
287 data_bit = 1;
288 }
289 crc_bit = crc >> 15 & 0xff;
290 crc <<= 1 & 0xffff;
291 if data_bit != crc_bit {
292 crc ^= POLYNOM;
293 }
294 }
295 }
296 crc
297}
298
299#[cfg(test)]
300mod tests {
301 use super::*;
302 use crate::constants::ATCA_CMD_SIZE_MAX;
303
304 #[test]
305 fn info() {
306 let packet = EccCommand::info();
307 let mut buf = BytesMut::with_capacity(ATCA_CMD_SIZE_MAX as usize);
308 buf.put_u8(0x03); packet.bytes_into(&mut buf);
310 assert_eq!(&[0x03, 0x07, 0x30, 0x00, 0x00, 0x00, 0x03, 0x5D], &buf[..])
312 }
313}