1extern crate libc;
16
17#[cfg(any(
18 all(feature = "android", target_os = "android"),
19 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
20))]
21use libc::{c_int, c_void, size_t};
22
23#[cfg(any(
24 all(feature = "android", target_os = "android"),
25 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
26))]
27extern "C" {
28 fn platform_icc_open_channel(aid_bytes: *const u8, aid_size: size_t) -> c_int;
29 fn platform_icc_exchange_apdu(
30 channel: c_int,
31 cla: u8,
32 ins: u8,
33 p1: u8,
34 p2: u8,
35 p3: u8,
36 in_data: *const u8,
37 in_size: size_t,
38 out_size: *mut size_t,
39 ) -> *const u8;
40 fn platform_icc_close_channel(channel: c_int);
41}
42
43pub struct IccChannel {
44 channel: i32,
45}
46
47impl IccChannel {
48 #[cfg(any(
49 all(feature = "android", target_os = "android"),
50 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
51 ))]
52 pub fn new(aid_bytes: &[u8]) -> Option<IccChannel> {
53 unsafe {
54 let channel = platform_icc_open_channel(aid_bytes.as_ptr(), aid_bytes.len());
55 if channel >= 0 {
56 Some(IccChannel { channel })
57 } else {
58 None
59 }
60 }
61 }
62
63 #[cfg(not(any(
64 all(feature = "android", target_os = "android"),
65 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
66 )))]
67 pub fn new(aid_bytes: &[u8]) -> Option<IccChannel> {
68 None
69 }
70
71 #[cfg(any(
72 all(feature = "android", target_os = "android"),
73 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
74 ))]
75 pub fn icc_exchange_apdu(
76 &self,
77 cla: u8,
78 ins: u8,
79 p1: u8,
80 p2: u8,
81 p3: u8,
82 in_data: &[u8],
83 ) -> Result<Vec<u8>, ErrorKind> {
84 unsafe {
85 let mut out_size: size_t = 0;
86 let out_data = platform_icc_exchange_apdu(
87 self.channel,
88 cla,
89 ins,
90 p1,
91 p2,
92 p3,
93 in_data.as_ptr(),
94 in_data.len(),
95 &mut out_size,
96 );
97
98 if out_size <= 0 || out_data == std::ptr::null() {
99 return Err(ErrorKind::InvocationFailure);
100 }
101
102 let mut data = Vec::with_capacity(out_size);
103
104 std::ptr::copy_nonoverlapping(out_data, data.as_mut_ptr(), out_size);
105
106 libc::free(out_data as *mut c_void);
107
108 data.set_len(out_size);
109
110 Ok(data)
111 }
112 }
113
114 #[cfg(not(any(
115 all(feature = "android", target_os = "android"),
116 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
117 )))]
118 pub fn icc_exchange_apdu(
119 &self,
120 cla: u8,
121 ins: u8,
122 p1: u8,
123 p2: u8,
124 p3: u8,
125 in_data: &[u8],
126 ) -> Result<Vec<u8>, ErrorKind> {
127 Err(ErrorKind::InvocationFailure)
128 }
129}
130
131impl Drop for IccChannel {
132 fn drop(&mut self) {
133 #[cfg(any(
134 all(feature = "android", target_os = "android"),
135 all(feature = "ohos", all(target_os = "linux", target_env = "ohos"))
136 ))]
137 unsafe {
138 platform_icc_close_channel(self.channel)
139 }
140 }
141}
142
143pub enum ErrorKind {
144 InvocationFailure,
145}