ledger_proto/apdus/
device_info.rs1use encdec::{Decode, Encode};
2
3use crate::{ApduError, ApduStatic};
4
5#[derive(Copy, Clone, PartialEq, Debug, Default, Encode, Decode)]
7#[encdec(error = "ApduError")]
8pub struct DeviceInfoReq {}
9
10impl ApduStatic for DeviceInfoReq {
11 const CLA: u8 = 0xe0;
13
14 const INS: u8 = 0x01;
16}
17
18#[derive(Copy, Clone, PartialEq, Debug)]
20pub struct DeviceInfoResp<'a> {
21 pub target_id: [u8; 4],
23
24 pub se_version: &'a str,
26
27 pub flags: &'a [u8],
29
30 pub mcu_version: &'a str,
32}
33
34impl<'a> DeviceInfoResp<'a> {
35 pub fn new(
37 target_id: [u8; 4],
38 se_version: &'a str,
39 mcu_version: &'a str,
40 flags: &'a [u8],
41 ) -> Self {
42 Self {
43 target_id,
44 se_version,
45 mcu_version,
46 flags,
47 }
48 }
49}
50
51impl<'a> Encode for DeviceInfoResp<'a> {
52 type Error = ApduError;
53
54 fn encode(&self, buff: &mut [u8]) -> Result<usize, ApduError> {
56 if buff.len() < self.encode_len()? {
58 return Err(ApduError::InvalidLength);
59 }
60
61 let mut index = 0;
62
63 buff[index..][..4].copy_from_slice(&self.target_id);
65 index += 4;
66
67 buff[index] = self.se_version.len() as u8;
69 buff[index + 1..][..self.se_version.len()].copy_from_slice(self.se_version.as_bytes());
70 index += 1 + self.se_version.len();
71
72 buff[index] = self.flags.len() as u8;
74 buff[index + 1..][..self.flags.len()].copy_from_slice(self.flags);
75 index += 1 + self.flags.len();
76
77 buff[index] = self.mcu_version.len() as u8;
79 buff[index + 1..][..self.mcu_version.len()].copy_from_slice(self.mcu_version.as_bytes());
80 index += 1 + self.mcu_version.len();
81
82 Ok(index)
83 }
84
85 fn encode_len(&self) -> Result<usize, ApduError> {
87 let mut len = 4;
88
89 len += 1 + self.se_version.len();
90 len += 1 + self.flags.len();
91 len += 1 + self.mcu_version.len();
92
93 Ok(len)
94 }
95}
96
97impl<'a> Decode<'a> for DeviceInfoResp<'a> {
98 type Output = Self;
99 type Error = ApduError;
100
101 fn decode(buff: &'a [u8]) -> Result<(Self, usize), ApduError> {
103 let mut index = 0;
104 let buff = buff;
105
106 let mut target_id = [0u8; 4];
108 target_id.copy_from_slice(&buff[..4]);
109 index += 4;
110
111 let se_version_len = buff[index] as usize;
113 let se_version = core::str::from_utf8(&buff[index + 1..][..se_version_len])
114 .map_err(|_| ApduError::InvalidUtf8)?;
115 index += 1 + se_version_len;
116
117 let flags_len = buff[index] as usize;
119 let flags = &buff[index + 1..][..flags_len];
120 index += 1 + flags_len;
121
122 let mcu_version_len = buff[index] as usize;
124 let mcu_version = core::str::from_utf8(&buff[index + 1..][..mcu_version_len])
125 .map_err(|_| ApduError::InvalidUtf8)?;
126 index += 1 + mcu_version_len;
127
128 Ok((
129 Self {
130 target_id,
131 se_version,
132 flags,
133 mcu_version,
134 },
135 index,
136 ))
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn device_info_resp() {
146 let r = DeviceInfoResp::new([0x01, 0x02, 0x03, 0x04], "SOME SE", "SOME MCU", &[0xaa]);
147
148 let mut buff = [0u8; 256];
149 crate::tests::encode_decode(&mut buff, r);
150 }
151}