rust_rcs_core/ffi/
icc.rs

1// Copyright 2023 宋昊文
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15extern 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}