1use defmt::{info, warn};
43use embassy_futures::select::{select, Either};
44use embassy_time::{Duration, Timer};
45
46use atecc608b::AteccErrorKind;
47use atecc608b::AteccHal;
48use atecc608b::Slot;
49use hsm_crypto_service::{Clock, CryptoService, CryptoServiceError};
50use hsm_firmware_logic::{Event, TOUCH_TIMEOUT_MS};
51use hsm_usb_protocol::commands::
52{
53 parse_emergency_reset, parse_lock_config_zone, parse_lock_data_zone, parse_lock_slot,
54 parse_provision_slot, parse_read_slot_block, parse_read_slot_word, parse_set_pin,
55 parse_set_puk, parse_sign, parse_slot_only, parse_unblock_pin, parse_verify_pin,
56 parse_write_config_zone, CommandOpcode,
57};
58use hsm_usb_protocol::responses::ResponseStatus;
59use hsm_usb_protocol::Frame;
60
61use crate::channels::{post_event, TOUCH_CONFIRMED};
62use crate::usb::{HidRx, HidTx, REPORT_SIZE, UsbStack};
63
64#[embassy_executor::task]
66pub(crate) async fn usb_run_task(mut usb: UsbStack<'static>) -> !
67{
68 usb.run().await
69}
70
71pub(crate) async fn dispatch_loop<H, C>
77(
78 mut rx: HidRx<'static>,
79 mut tx: HidTx<'static>,
80 mut service: CryptoService<H, C>,
81) -> !
82where
83 H: AteccHal,
84 C: Clock,
85 H::Error: core::fmt::Debug,
86{
87 let mut rx_buf = [0u8; REPORT_SIZE];
88 let mut tx_buf = [0u8; REPORT_SIZE];
89
90 loop
91 {
92 let n = match rx.read(&mut rx_buf).await
93 {
94 Ok(n) => n,
95 Err(_) =>
96 {
97 warn!("usb hid read error, restarting loop");
98 continue;
99 }
100 };
101
102 if n != REPORT_SIZE
103 {
104 warn!("unexpected short hid report ({} bytes), discarding", n);
105 continue;
106 }
107
108 let response_len = handle_one_request(&mut service, &rx_buf, &mut tx_buf).await;
109
110 if tx.write(&tx_buf[..response_len]).await.is_err()
111 {
112 warn!("usb hid write error");
113 }
114 }
115}
116
117async fn handle_one_request<H, C>
124(
125 service: &mut CryptoService<H, C>,
126 rx_buf: &[u8],
127 tx_buf: &mut [u8],
128) -> usize
129where
130 H: AteccHal,
131 C: Clock,
132 H::Error: core::fmt::Debug,
133{
134 let frame = match Frame::parse(rx_buf)
135 {
136 Ok(f) => f,
137 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
138 };
139
140 let opcode = match CommandOpcode::try_from(frame.opcode)
141 {
142 Ok(op) => op,
143 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidCommand, &[]),
144 };
145
146 info!("dispatching opcode {:#x}", opcode as u8);
147
148 match opcode
149 {
150 CommandOpcode::Info => handle_info(service, tx_buf).await,
151 CommandOpcode::GetPubkey => handle_get_pubkey(service, frame.payload, tx_buf).await,
152 CommandOpcode::Sign => handle_sign(service, frame.payload, tx_buf).await,
153 CommandOpcode::GenKey => handle_genkey(service, frame.payload, tx_buf).await,
154 CommandOpcode::ReadConfigZone =>
155 {
156 handle_read_config_zone(service, frame.payload, tx_buf).await
157 }
158 CommandOpcode::VerifyPin => handle_verify_pin(service, frame.payload, tx_buf).await,
159 CommandOpcode::SetPin => handle_set_pin(service, frame.payload, tx_buf).await,
160 CommandOpcode::UnblockPin => handle_unblock_pin(service, frame.payload, tx_buf).await,
161 CommandOpcode::GetPinStatus => handle_get_pin_status(service, tx_buf).await,
162 CommandOpcode::SetPuk => handle_set_puk(service, frame.payload, tx_buf).await,
163 CommandOpcode::CloseSession => handle_close_session(service, tx_buf),
164 CommandOpcode::EmergencyReset =>
165 {
166 handle_emergency_reset(service, frame.payload, tx_buf).await
167 }
168 CommandOpcode::ReadSlotBlock =>
169 {
170 handle_read_slot_block(service, frame.payload, tx_buf).await
171 }
172 CommandOpcode::ReadSlotWord =>
173 {
174 handle_read_slot_word(service, frame.payload, tx_buf).await
175 }
176 CommandOpcode::ReadConfigSlot =>
177 {
178 handle_read_config_slot(service, frame.payload, tx_buf).await
179 }
180 CommandOpcode::WriteConfigZone =>
181 {
182 handle_write_config_zone(service, frame.payload, tx_buf).await
183 }
184 CommandOpcode::ProvisionSlot =>
185 {
186 handle_provision_slot(service, frame.payload, tx_buf).await
187 }
188 CommandOpcode::ProvisionInitialPin =>
189 {
190 handle_provision_initial_pin(service, tx_buf).await
191 }
192 CommandOpcode::ProvisionInitialPuk =>
193 {
194 handle_provision_initial_puk(service, tx_buf).await
195 }
196 CommandOpcode::ProvisionIoKey =>
197 {
198 handle_provision_io_key(service, tx_buf).await
199 }
200 CommandOpcode::ReadCounter =>
201 {
202 handle_read_counter(service, frame.payload, tx_buf).await
203 }
204 CommandOpcode::LockConfigZone =>
205 {
206 handle_lock_config_zone(service, frame.payload, tx_buf).await
207 }
208 CommandOpcode::LockDataZone =>
209 {
210 handle_lock_data_zone(service, frame.payload, tx_buf).await
211 }
212 CommandOpcode::LockSlot =>
213 {
214 handle_lock_slot(service, frame.payload, tx_buf).await
215 }
216 }
217}
218
219async fn handle_info<H, C>
220(
221 service: &mut CryptoService<H, C>,
222 tx_buf: &mut [u8],
223) -> usize
224where
225 H: AteccHal,
226 C: Clock,
227 H::Error: core::fmt::Debug,
228{
229 match service.info().await
230 {
231 Ok(info) =>
232 {
233 let mut payload = [0u8; 14];
235 payload[0..4].copy_from_slice(&info.revision);
236 payload[4..13].copy_from_slice(&info.serial);
237 payload[13] = u8::from(info.is_provisioned);
238 write_status(tx_buf, ResponseStatus::Ok, &payload)
239 }
240 Err(err) => write_error(tx_buf, &err),
241 }
242}
243
244async fn handle_get_pubkey<H, C>
245(
246 service: &mut CryptoService<H, C>,
247 payload: &[u8],
248 tx_buf: &mut [u8],
249) -> usize
250where
251 H: AteccHal,
252 C: Clock,
253 H::Error: core::fmt::Debug,
254{
255 let slot = match parse_slot_only(payload)
256 {
257 Ok(s) => s,
258 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
259 };
260 let slot = match Slot::new(slot)
261 {
262 Some(s) => s,
263 None => return write_status(tx_buf, ResponseStatus::InvalidSlot, &[]),
264 };
265 match service.get_pubkey(slot).await
266 {
267 Ok(pk) => write_status(tx_buf, ResponseStatus::Ok, &pk),
268 Err(err) => write_error(tx_buf, &err),
269 }
270}
271
272async fn handle_sign<H, C>
273(
274 service: &mut CryptoService<H, C>,
275 payload: &[u8],
276 tx_buf: &mut [u8],
277) -> usize
278where
279 H: AteccHal,
280 C: Clock,
281 H::Error: core::fmt::Debug,
282{
283 let (slot_idx, digest) = match parse_sign(payload)
284 {
285 Ok(v) => v,
286 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
287 };
288 let slot = match Slot::new(slot_idx)
289 {
290 Some(s) => s,
291 None => return write_status(tx_buf, ResponseStatus::InvalidSlot, &[]),
292 };
293
294 if !service.is_session_active()
297 {
298 return write_status(tx_buf, ResponseStatus::PinRequired, &[]);
299 }
300
301 TOUCH_CONFIRMED.reset();
304
305 post_event(Event::SignRequested);
307
308 let timeout = Timer::after(Duration::from_millis(TOUCH_TIMEOUT_MS));
311 let confirmation = TOUCH_CONFIRMED.wait();
312 match select(timeout, confirmation).await
313 {
314 Either::First(()) =>
315 {
316 info!("touch timeout, cancelling sign");
317 post_event(Event::TouchTimeout);
318 return write_status(tx_buf, ResponseStatus::TouchTimeout, &[]);
319 }
320 Either::Second(()) =>
321 {
322 }
324 }
325
326 let result = service.sign(slot, &digest).await;
329 post_event(Event::SignComplete);
330
331 match result
332 {
333 Ok(sig) => write_status(tx_buf, ResponseStatus::Ok, &sig),
334 Err(err) =>
335 {
336 post_event(Event::ErrorRaised);
337 write_error(tx_buf, &err)
338 }
339 }
340}
341
342async fn handle_genkey<H, C>
343(
344 service: &mut CryptoService<H, C>,
345 payload: &[u8],
346 tx_buf: &mut [u8],
347) -> usize
348where
349 H: AteccHal,
350 C: Clock,
351 H::Error: core::fmt::Debug,
352{
353 let slot_idx = match parse_slot_only(payload)
355 {
356 Ok(s) => s,
357 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
358 };
359 let slot = match Slot::new(slot_idx)
360 {
361 Some(s) => s,
362 None => return write_status(tx_buf, ResponseStatus::InvalidSlot, &[]),
363 };
364 match service.genkey_create(slot).await
365 {
366 Ok(pubkey) => write_status(tx_buf, ResponseStatus::Ok, &pubkey),
367 Err(err) => write_error(tx_buf, &err),
368 }
369}
370
371async fn handle_read_config_zone<H, C>
372(
373 service: &mut CryptoService<H, C>,
374 payload: &[u8],
375 tx_buf: &mut [u8],
376) -> usize
377where
378 H: AteccHal,
379 C: Clock,
380 H::Error: core::fmt::Debug,
381{
382 let block = match parse_slot_only(payload)
384 {
385 Ok(b) => b,
386 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
387 };
388 match service.read_config_block(block).await
389 {
390 Ok(data) => write_status(tx_buf, ResponseStatus::Ok, &data),
391 Err(err) => write_error(tx_buf, &err),
392 }
393}
394
395async fn handle_read_config_slot<H, C>
396(
397 service: &mut CryptoService<H, C>,
398 payload: &[u8],
399 tx_buf: &mut [u8],
400) -> usize
401where
402 H: AteccHal,
403 C: Clock,
404 H::Error: core::fmt::Debug,
405{
406 let slot_idx = match parse_slot_only(payload)
408 {
409 Ok(s) => s,
410 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
411 };
412 let slot = match Slot::new(slot_idx)
413 {
414 Some(s) => s,
415 None => return write_status(tx_buf, ResponseStatus::InvalidSlot, &[]),
416 };
417 match service.read_config_slot(slot).await
418 {
419 Ok(data) => write_status(tx_buf, ResponseStatus::Ok, &data),
420 Err(err) => write_error(tx_buf, &err),
421 }
422}
423
424async fn handle_write_config_zone<H, C>
425(
426 service: &mut CryptoService<H, C>,
427 payload: &[u8],
428 tx_buf: &mut [u8],
429) -> usize
430where
431 H: AteccHal,
432 C: Clock,
433 H::Error: core::fmt::Debug,
434{
435 let (block, data) = match parse_write_config_zone(payload)
438 {
439 Ok(v) => v,
440 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
441 };
442 match service.write_config_block(block, &data).await
443 {
444 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
445 Err(err) => write_error(tx_buf, &err),
446 }
447}
448
449async fn handle_provision_slot<H, C>
450(
451 service: &mut CryptoService<H, C>,
452 payload: &[u8],
453 tx_buf: &mut [u8],
454) -> usize
455where
456 H: AteccHal,
457 C: Clock,
458 H::Error: core::fmt::Debug,
459{
460 let (slot_idx, value) = match parse_provision_slot(payload)
464 {
465 Ok(v) => v,
466 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
467 };
468 let slot = match Slot::new(slot_idx)
469 {
470 Some(s) => s,
471 None => return write_status(tx_buf, ResponseStatus::InvalidSlot, &[]),
472 };
473 match service.provision_slot(slot, &value).await
474 {
475 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
476 Err(err) => write_error(tx_buf, &err),
477 }
478}
479
480async fn handle_provision_initial_pin<H, C>
481(
482 service: &mut CryptoService<H, C>,
483 tx_buf: &mut [u8],
484) -> usize
485where
486 H: AteccHal,
487 C: Clock,
488 H::Error: core::fmt::Debug,
489{
490 match service.provision_initial_pin().await
491 {
492 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
493 Err(err) => write_error(tx_buf, &err),
494 }
495}
496
497async fn handle_provision_initial_puk<H, C>
498(
499 service: &mut CryptoService<H, C>,
500 tx_buf: &mut [u8],
501) -> usize
502where
503 H: AteccHal,
504 C: Clock,
505 H::Error: core::fmt::Debug,
506{
507 match service.provision_initial_puk().await
508 {
509 Ok(puk) => write_status(tx_buf, ResponseStatus::Ok, &puk),
510 Err(err) => write_error(tx_buf, &err),
511 }
512}
513
514async fn handle_provision_io_key<H, C>
515(
516 service: &mut CryptoService<H, C>,
517 tx_buf: &mut [u8],
518) -> usize
519where
520 H: AteccHal,
521 C: Clock,
522 H::Error: core::fmt::Debug,
523{
524 match service.provision_initial_io_key().await
525 {
526 Ok(io_key) => write_status(tx_buf, ResponseStatus::Ok, &io_key),
527 Err(err) => write_error(tx_buf, &err),
528 }
529}
530
531async fn handle_lock_config_zone<H, C>
547(
548 service: &mut CryptoService<H, C>,
549 payload: &[u8],
550 tx_buf: &mut [u8],
551) -> usize
552where
553 H: AteccHal,
554 C: Clock,
555 H::Error: core::fmt::Debug,
556{
557 let expected_crc = match parse_lock_config_zone(payload)
558 {
559 Ok(v) => v,
560 Err(hsm_usb_protocol::commands::PayloadError::MagicMismatch) =>
561 {
562 return write_status(tx_buf, ResponseStatus::LockMagicMismatch, &[]);
563 }
564 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
565 };
566 match service.lock_config_zone(expected_crc).await
567 {
568 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
569 Err(err) => write_lock_error(tx_buf, &err),
570 }
571}
572
573async fn handle_lock_data_zone<H, C>
574(
575 service: &mut CryptoService<H, C>,
576 payload: &[u8],
577 tx_buf: &mut [u8],
578) -> usize
579where
580 H: AteccHal,
581 C: Clock,
582 H::Error: core::fmt::Debug,
583{
584 match parse_lock_data_zone(payload)
585 {
586 Ok(()) => {}
587 Err(hsm_usb_protocol::commands::PayloadError::MagicMismatch) =>
588 {
589 return write_status(tx_buf, ResponseStatus::LockMagicMismatch, &[]);
590 }
591 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
592 }
593 match service.lock_data_zone().await
594 {
595 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
596 Err(err) => write_lock_error(tx_buf, &err),
597 }
598}
599
600async fn handle_lock_slot<H, C>
601(
602 service: &mut CryptoService<H, C>,
603 payload: &[u8],
604 tx_buf: &mut [u8],
605) -> usize
606where
607 H: AteccHal,
608 C: Clock,
609 H::Error: core::fmt::Debug,
610{
611 let slot_idx = match parse_lock_slot(payload)
612 {
613 Ok(v) => v,
614 Err(hsm_usb_protocol::commands::PayloadError::MagicMismatch) =>
615 {
616 return write_status(tx_buf, ResponseStatus::LockMagicMismatch, &[]);
617 }
618 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
619 };
620 let slot = match Slot::new(slot_idx)
621 {
622 Some(s) => s,
623 None => return write_status(tx_buf, ResponseStatus::InvalidSlot, &[]),
624 };
625 match service.lock_slot(slot).await
626 {
627 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
628 Err(err) => write_lock_error(tx_buf, &err),
629 }
630}
631
632fn write_lock_error<HalError>
638(
639 tx_buf: &mut [u8],
640 err: &CryptoServiceError<HalError>,
641) -> usize
642where
643 HalError: core::fmt::Debug,
644{
645 use atecc608b::{AteccError, ChipError};
646 use CryptoServiceError as E;
647
648 if let E::Atecc(AteccError::Chip(ChipError::ExecutionError)) = err
649 {
650 return write_status(tx_buf, ResponseStatus::LockCrcMismatch, &[]);
651 }
652 write_error(tx_buf, err)
653}
654
655async fn handle_verify_pin<H, C>
656(
657 service: &mut CryptoService<H, C>,
658 payload: &[u8],
659 tx_buf: &mut [u8],
660) -> usize
661where
662 H: AteccHal,
663 C: Clock,
664 H::Error: core::fmt::Debug,
665{
666 let pin = match parse_verify_pin(payload)
667 {
668 Ok(p) => p,
669 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
670 };
671 match service.verify_pin(&pin).await
672 {
673 Ok(()) =>
674 {
675 post_event(Event::PinVerified);
676 write_status(tx_buf, ResponseStatus::Ok, &[])
677 }
678 Err(err) => write_error(tx_buf, &err),
679 }
680}
681
682async fn handle_set_pin<H, C>
683(
684 service: &mut CryptoService<H, C>,
685 payload: &[u8],
686 tx_buf: &mut [u8],
687) -> usize
688where
689 H: AteccHal,
690 C: Clock,
691 H::Error: core::fmt::Debug,
692{
693 let (old, new, io_key) = match parse_set_pin(payload)
694 {
695 Ok(v) => v,
696 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
697 };
698 match service.set_pin(&old, &new, &io_key).await
699 {
700 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
701 Err(err) => write_error(tx_buf, &err),
702 }
703}
704
705async fn handle_unblock_pin<H, C>
706(
707 service: &mut CryptoService<H, C>,
708 payload: &[u8],
709 tx_buf: &mut [u8],
710) -> usize
711where
712 H: AteccHal,
713 C: Clock,
714 H::Error: core::fmt::Debug,
715{
716 let (puk, new_pin, io_key) = match parse_unblock_pin(payload)
717 {
718 Ok(v) => v,
719 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
720 };
721 match service.unblock_pin(&puk, &new_pin, &io_key).await
722 {
723 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
724 Err(err) => write_error(tx_buf, &err),
725 }
726}
727
728async fn handle_set_puk<H, C>
729(
730 service: &mut CryptoService<H, C>,
731 payload: &[u8],
732 tx_buf: &mut [u8],
733) -> usize
734where
735 H: AteccHal,
736 C: Clock,
737 H::Error: core::fmt::Debug,
738{
739 let (old, new, io_key) = match parse_set_puk(payload)
740 {
741 Ok(v) => v,
742 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
743 };
744 match service.set_puk(&old, &new, &io_key).await
745 {
746 Ok(()) => write_status(tx_buf, ResponseStatus::Ok, &[]),
747 Err(err) => write_error(tx_buf, &err),
748 }
749}
750
751async fn handle_emergency_reset<H, C>
758(
759 service: &mut CryptoService<H, C>,
760 payload: &[u8],
761 tx_buf: &mut [u8],
762) -> usize
763where
764 H: AteccHal,
765 C: Clock,
766 H::Error: core::fmt::Debug,
767{
768 let io_key = match parse_emergency_reset(payload)
769 {
770 Ok(v) => v,
771 Err(hsm_usb_protocol::commands::PayloadError::MagicMismatch) =>
772 {
773 return write_status(tx_buf, ResponseStatus::LockMagicMismatch, &[]);
774 }
775 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
776 };
777 match service.emergency_reset(&io_key).await
778 {
779 Ok(new_puk) => write_status(tx_buf, ResponseStatus::Ok, &new_puk),
780 Err(err) => write_error(tx_buf, &err),
781 }
782}
783
784fn handle_close_session<H, C>
787(
788 service: &mut CryptoService<H, C>,
789 tx_buf: &mut [u8],
790) -> usize
791where
792 H: AteccHal,
793 C: Clock,
794 H::Error: core::fmt::Debug,
795{
796 service.close_session();
797 write_status(tx_buf, ResponseStatus::Ok, &[])
798}
799
800async fn handle_read_slot_block<H, C>
801(
802 service: &mut CryptoService<H, C>,
803 payload: &[u8],
804 tx_buf: &mut [u8],
805) -> usize
806where
807 H: AteccHal,
808 C: Clock,
809 H::Error: core::fmt::Debug,
810{
811 let (slot_idx, block) = match parse_read_slot_block(payload)
812 {
813 Ok(v) => v,
814 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
815 };
816 let slot = match Slot::new(slot_idx)
817 {
818 Some(s) => s,
819 None => return write_status(tx_buf, ResponseStatus::InvalidSlot, &[]),
820 };
821 match service.read_slot_block(slot, block).await
822 {
823 Ok(data) => write_status(tx_buf, ResponseStatus::Ok, &data),
824 Err(err) => write_error(tx_buf, &err),
825 }
826}
827
828async fn handle_read_slot_word<H, C>
829(
830 service: &mut CryptoService<H, C>,
831 payload: &[u8],
832 tx_buf: &mut [u8],
833) -> usize
834where
835 H: AteccHal,
836 C: Clock,
837 H::Error: core::fmt::Debug,
838{
839 let (slot_idx, block, offset) = match parse_read_slot_word(payload)
840 {
841 Ok(v) => v,
842 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
843 };
844 let slot = match Slot::new(slot_idx)
845 {
846 Some(s) => s,
847 None => return write_status(tx_buf, ResponseStatus::InvalidSlot, &[]),
848 };
849 match service.read_slot_word(slot, block, offset).await
850 {
851 Ok(data) => write_status(tx_buf, ResponseStatus::Ok, &data),
852 Err(err) => write_error(tx_buf, &err),
853 }
854}
855
856async fn handle_get_pin_status<H, C>
857(
858 service: &mut CryptoService<H, C>,
859 tx_buf: &mut [u8],
860) -> usize
861where
862 H: AteccHal,
863 C: Clock,
864 H::Error: core::fmt::Debug,
865{
866 match service.get_pin_status().await
867 {
868 Ok(status) =>
869 {
870 let payload = [
871 status.pin_tries_remaining,
872 status.puk_tries_remaining,
873 u8::from(status.session_active),
874 ];
875 write_status(tx_buf, ResponseStatus::Ok, &payload)
876 }
877 Err(err) => write_error(tx_buf, &err),
878 }
879}
880
881async fn handle_read_counter<H, C>
892(
893 service: &mut CryptoService<H, C>,
894 payload: &[u8],
895 tx_buf: &mut [u8],
896) -> usize
897where
898 H: AteccHal,
899 C: Clock,
900 H::Error: core::fmt::Debug,
901{
902 let counter_byte = match parse_slot_only(payload)
903 {
904 Ok(b) => b,
905 Err(_) => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
906 };
907 let counter = match counter_byte
908 {
909 0 => atecc608b::command::counter::CounterId::Counter0,
910 1 => atecc608b::command::counter::CounterId::Counter1,
911 _ => return write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
912 };
913 match service.read_counter(counter).await
914 {
915 Ok(value) =>
916 {
917 let bytes = value.to_le_bytes();
918 write_status(tx_buf, ResponseStatus::Ok, &bytes)
919 }
920 Err(err) => write_error(tx_buf, &err),
921 }
922}
923
924fn write_error<HalError>
937(
938 tx_buf: &mut [u8],
939 err: &CryptoServiceError<HalError>,
940) -> usize
941where
942 HalError: core::fmt::Debug,
943{
944 use CryptoServiceError as E;
945 match err
946 {
947 E::Atecc(atecc_err) => match atecc_err.kind()
948 {
949 AteccErrorKind::Chip(chip_err) =>
950 {
951 write_status
952 (
953 tx_buf,
954 ResponseStatus::AteccChipError,
955 &[chip_err.as_status_byte()],
956 )
957 }
958 other =>
959 {
960 write_status
961 (
962 tx_buf,
963 ResponseStatus::AteccCommunicationError,
964 &[other.as_sub_code()],
965 )
966 }
967 },
968 E::InvalidFormat(_) => write_status(tx_buf, ResponseStatus::InvalidPayload, &[]),
969 E::PinIncorrect { tries_remaining } =>
970 {
971 write_status(tx_buf, ResponseStatus::WrongPin, &[*tries_remaining])
972 }
973 E::PinBlocked => write_status(tx_buf, ResponseStatus::PinBlocked, &[]),
974 E::PukIncorrect { tries_remaining } =>
975 {
976 write_status(tx_buf, ResponseStatus::WrongPuk, &[*tries_remaining])
977 }
978 E::Bricked => write_status(tx_buf, ResponseStatus::Bricked, &[]),
979 E::PinRequired => write_status(tx_buf, ResponseStatus::PinRequired, &[]),
980 E::NotProvisioned => write_status(tx_buf, ResponseStatus::NotProvisioned, &[]),
981 E::EmergencyResetNotPermitted { pin_tries_remaining, puk_tries_remaining } =>
982 {
983 write_status(
984 tx_buf,
985 ResponseStatus::EmergencyResetNotPermitted,
986 &[*pin_tries_remaining, *puk_tries_remaining],
987 )
988 }
989 E::InvalidSlot { slot } =>
990 {
991 write_status(tx_buf, ResponseStatus::InvalidSlot, &[slot.as_u8()])
992 }
993 }
994}
995
996fn write_status(tx_buf: &mut [u8], status: ResponseStatus, payload: &[u8]) -> usize
998{
999 if Frame::write(status.as_u8(), payload, tx_buf).is_err()
1003 {
1004 let _ = Frame::write(ResponseStatus::InvalidPayload.as_u8(), &[], tx_buf);
1006 }
1007 REPORT_SIZE
1008}