iota_ledger_nano/ledger/ledger_apdu/mod.rs
1/*******************************************************************************
2* (c) 2022 Zondax AG
3*
4* Licensed under the Apache License, Version 2.0 (the "License");
5* you may not use this file except in compliance with the License.
6* You may obtain a copy of the License at
7*
8* http://www.apache.org/licenses/LICENSE-2.0
9*
10* Unless required by applicable law or agreed to in writing, software
11* distributed under the License is distributed on an "AS IS" BASIS,
12* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13* See the License for the specific language governing permissions and
14* limitations under the License.
15********************************************************************************/
16// changes: removed code we don't need
17//! This crate contains a couple of utilities to talk via the APDU protocol to Ledger devices
18
19use core::ops::Deref;
20
21#[derive(Debug, Clone)]
22/// An APDU command
23pub struct APDUCommand<B> {
24 ///APDU Class
25 ///
26 /// An incorrect APDU Class will prevent you from communicating with the device
27 pub cla: u8,
28 ///APDU Instruction
29 pub ins: u8,
30 ///First parameter of instruction
31 pub p1: u8,
32 ///Second parameter of instruction
33 pub p2: u8,
34 ///Payload of the instruction, can be empty
35 pub data: B,
36}
37
38impl<B> APDUCommand<B>
39where
40 B: Deref<Target = [u8]>,
41{
42 /// Serialize this [APDUCommand] to be sent to the device
43 pub fn serialize(&self) -> std::vec::Vec<u8> {
44 let mut v = std::vec![self.cla, self.ins, self.p1, self.p2, self.data.len() as u8];
45 v.extend(self.data.iter());
46 v
47 }
48}
49
50#[derive(Debug)]
51/// An APDU answer, whole last 2 bytes are interpreted as `retcode`
52pub struct APDUAnswer<B> {
53 data: B,
54 retcode: u16,
55}
56
57#[derive(Debug, PartialEq, Eq)]
58/// Error interpreting bytes as an APDU answer
59pub enum APDUAnswerError {
60 /// Passed APDU answer was less than the minimum 2 bytes required for the return code
61 TooShort,
62}
63
64impl<B> APDUAnswer<B>
65where
66 B: std::ops::Deref<Target = [u8]>,
67{
68 /// Attempt to interpret the given slice as an APDU answer
69 pub fn from_answer(answer: B) -> Result<Self, APDUAnswerError> {
70 if answer.len() < 2 {
71 return Err(APDUAnswerError::TooShort);
72 }
73 let retcode = arrayref::array_ref!(answer, answer.len() - 2, 2);
74 let retcode = u16::from_be_bytes(*retcode);
75
76 Ok(APDUAnswer {
77 data: answer,
78 retcode,
79 })
80 }
81
82 /// Will return the answer's payload
83 #[inline(always)]
84 pub fn apdu_data(&self) -> &[u8] {
85 &self.data[..self.data.len() - 2]
86 }
87
88 /// Will return the answer's payload
89 #[inline(always)]
90 pub fn data(&self) -> &[u8] {
91 self.apdu_data()
92 }
93
94 /// Returns the raw return code
95 #[inline(always)]
96 pub fn retcode(&self) -> u16 {
97 self.retcode
98 }
99}