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}