1use crate::error::*;
7mod ioctl;
8pub use ioctl::*;
9mod types;
10use rand::Rng;
11use std::fs::{File, OpenOptions};
12pub use types::*;
13
14pub mod rtmr;
15pub use rtmr::*;
16
17pub struct CsvGuest(File);
19
20impl CsvGuest {
21 pub fn open() -> std::io::Result<CsvGuest> {
23 let file = OpenOptions::new().read(true).open("/dev/csv-guest")?;
24 Ok(CsvGuest(file))
25 }
26
27 pub fn get_report(
35 &mut self,
36 data: Option<[u8; 64]>,
37 mnonce: Option<[u8; 16]>,
38 ) -> Result<AttestationReportWrapper, Error> {
39 let mut mnonce_value = [0u8; 16];
40 if let Some(mnonce) = mnonce {
41 mnonce_value = mnonce;
42 } else {
43 let mut rng = rand::thread_rng();
44 for element in &mut mnonce_value {
45 *element = rng.gen();
46 }
47 }
48
49 let report_request = ReportReq::new(data, mnonce_value)?;
50
51 let mut report_response = AttestationReportV1::default();
52
53 let request_bytes: &[u8] = unsafe {
55 let req_ptr = &report_request as *const ReportReq as *const u8;
56 std::slice::from_raw_parts(req_ptr, std::mem::size_of::<ReportReq>())
57 };
58
59 let response_bytes: &mut [u8] = unsafe {
60 let rsp_ptr = &mut report_response as *mut AttestationReportV1 as *mut u8;
61 std::slice::from_raw_parts_mut(rsp_ptr, std::mem::size_of::<AttestationReportV1>())
62 };
63
64 response_bytes[..request_bytes.len()].copy_from_slice(request_bytes);
66
67 let mut guest_report_request = GuestReportRequest::new(response_bytes);
68
69 CSV_GET_REPORT.ioctl(&mut self.0, &mut guest_report_request)?;
70
71 report_response.signer.verify(
72 &mnonce_value,
73 &report_response.tee_info.mnonce,
74 &report_response.tee_info.anonce,
75 )?;
76
77 Ok(AttestationReportWrapper::new([0u8; 16], 0, response_bytes))
78 }
79
80 pub fn get_report_ext(
90 &mut self,
91 data: Option<[u8; 64]>,
92 mnonce: Option<[u8; 16]>,
93 flags: u32,
94 ) -> Result<AttestationReportWrapper, Error> {
95 if !self.check_attestation_report_v2_supported() {
96 self.get_report(data, mnonce)
97 } else if flags == 0 {
98 self.get_report(data, mnonce)
100 } else {
101 let mut mnonce_value = [0u8; 16];
102 if let Some(mnonce) = mnonce {
103 mnonce_value = mnonce;
104 } else {
105 let mut rng = rand::thread_rng();
106 for element in &mut mnonce_value {
107 *element = rng.gen();
108 }
109 }
110
111 let report_request = ReportReqExt::new(data, mnonce_value, flags)?;
112
113 let mut report_response = AttestationReportV2::default();
114
115 let request_bytes: &[u8] = unsafe {
117 let req_ptr = &report_request as *const ReportReqExt as *const u8;
118 std::slice::from_raw_parts(req_ptr, std::mem::size_of::<ReportReqExt>())
119 };
120
121 let response_bytes: &mut [u8] = unsafe {
122 let rsp_ptr = &mut report_response as *mut AttestationReportV2 as *mut u8;
123 std::slice::from_raw_parts_mut(rsp_ptr, std::mem::size_of::<AttestationReportV2>())
124 };
125
126 response_bytes[..request_bytes.len()].copy_from_slice(request_bytes);
128
129 let mut guest_report_request = GuestReportRequest::new(response_bytes);
130
131 CSV_GET_REPORT.ioctl(&mut self.0, &mut guest_report_request)?;
132
133 report_response
134 .signer
135 .verify(&mnonce_value, &report_response.tee_info.mnonce, &0)?;
136
137 Ok(AttestationReportWrapper::new(
138 ATTESTATION_EXT_MAGIC,
139 flags,
140 response_bytes,
141 ))
142 }
143 }
144
145 pub fn req_rtmr_status(&mut self) -> Result<CsvGuestUserRtmrStatus, std::io::Error> {
147 let mut rtmr_status = CsvGuestUserRtmrStatus::new();
148
149 let rtmr_status_bytes: &mut [u8] = unsafe {
150 std::slice::from_raw_parts_mut(
151 &mut rtmr_status as *mut _ as *mut u8,
152 std::mem::size_of::<CsvGuestUserRtmrStatus>(),
153 )
154 };
155
156 let mut rtmr_request =
157 GuestRtmrRequest::new(rtmr_status_bytes, CsvGuestUserRtmrSubcmd::Status);
158
159 match CSV_RTMR_REQ.ioctl(&mut self.0, &mut rtmr_request) {
160 Ok(return_code) => {
161 if return_code == 0 {
162 let fw_error_code = rtmr_request.get_fw_error_code();
163 if fw_error_code == 0 {
164 Ok(rtmr_status)
165 } else {
166 Err(std::io::Error::new(
167 std::io::ErrorKind::Other,
168 format!("rtmr_status fail, fw_err: {}", fw_error_code),
169 ))
170 }
171 } else {
172 Err(std::io::Error::new(
173 std::io::ErrorKind::Other,
174 format!("rtmr_status fail, rc: {}", return_code),
175 ))
176 }
177 }
178 Err(err) => Err(err),
179 }
180 }
181
182 pub fn req_rtmr_start(
184 &mut self,
185 version: u16,
186 ) -> Result<CsvGuestUserRtmrStart, std::io::Error> {
187 let mut rtmr_start = CsvGuestUserRtmrStart::new(version);
188
189 let rtmr_start_bytes: &mut [u8] = unsafe {
190 std::slice::from_raw_parts_mut(
191 &mut rtmr_start as *mut _ as *mut u8,
192 std::mem::size_of::<CsvGuestUserRtmrStart>(),
193 )
194 };
195
196 let mut rtmr_request =
197 GuestRtmrRequest::new(rtmr_start_bytes, CsvGuestUserRtmrSubcmd::Start);
198
199 match CSV_RTMR_REQ.ioctl(&mut self.0, &mut rtmr_request) {
200 Ok(return_code) => {
201 if return_code == 0 {
202 let fw_error_code = rtmr_request.get_fw_error_code();
203 if fw_error_code == 0 {
204 Ok(rtmr_start)
205 } else {
206 Err(std::io::Error::new(
207 std::io::ErrorKind::Other,
208 format!("rtmr_start fail, fw_err: {}", fw_error_code),
209 ))
210 }
211 } else {
212 Err(std::io::Error::new(
213 std::io::ErrorKind::Other,
214 format!("rtmr_start fail, rc: {}", return_code),
215 ))
216 }
217 }
218 Err(err) => Err(err),
219 }
220 }
221
222 pub fn req_rtmr_read(
224 &mut self,
225 bitmap: u32,
226 ) -> Result<(Box<[u8]>, &mut CsvGuestUserRtmrRead), std::io::Error> {
227 let mut num_regs: usize = 0;
228
229 for i in 0..CSV_RTMR_REG_NUM {
230 if bitmap & (1 << i) != 0 {
231 num_regs += 1;
232 }
233 }
234
235 let (mut _buffer, rtmr_read) =
236 CsvGuestUserRtmrRead::allocate_with_capacity(bitmap, num_regs);
237
238 let mut rtmr_request =
239 GuestRtmrRequest::new(_buffer.as_ref(), CsvGuestUserRtmrSubcmd::Read);
240
241 match CSV_RTMR_REQ.ioctl(&mut self.0, &mut rtmr_request) {
242 Ok(return_code) => {
243 if return_code == 0 {
244 let fw_error_code = rtmr_request.get_fw_error_code();
245 if fw_error_code == 0 {
246 Ok((_buffer, rtmr_read))
247 } else {
248 Err(std::io::Error::new(
249 std::io::ErrorKind::Other,
250 format!("rtmr_read fail, fw_err: {}", fw_error_code),
251 ))
252 }
253 } else {
254 Err(std::io::Error::new(
255 std::io::ErrorKind::Other,
256 format!("rtmr_read fail, rc: {}", return_code),
257 ))
258 }
259 }
260 Err(err) => Err(err),
261 }
262 }
263
264 pub fn req_rtmr_extend(
266 &mut self,
267 index: u8,
268 data: &[u8],
269 ) -> Result<CsvGuestUserRtmrExtend, std::io::Error> {
270 let mut rtmr_extend = CsvGuestUserRtmrExtend::new(index, data)?;
271
272 let rtmr_extend_bytes: &mut [u8] = unsafe {
273 std::slice::from_raw_parts_mut(
274 &mut rtmr_extend as *mut _ as *mut u8,
275 std::mem::size_of::<CsvGuestUserRtmrExtend>(),
276 )
277 };
278
279 let mut rtmr_request =
280 GuestRtmrRequest::new(rtmr_extend_bytes, CsvGuestUserRtmrSubcmd::Extend);
281
282 match CSV_RTMR_REQ.ioctl(&mut self.0, &mut rtmr_request) {
283 Ok(return_code) => {
284 if return_code == 0 {
285 let fw_error_code = rtmr_request.get_fw_error_code();
286 if fw_error_code == 0 {
287 Ok(rtmr_extend)
288 } else {
289 Err(std::io::Error::new(
290 std::io::ErrorKind::Other,
291 format!("rtmr_extend fail, fw_err: {}", fw_error_code),
292 ))
293 }
294 } else {
295 Err(std::io::Error::new(
296 std::io::ErrorKind::Other,
297 format!("rtmr_extend fail, rc: {}", return_code),
298 ))
299 }
300 }
301 Err(err) => Err(err),
302 }
303 }
304
305 pub fn check_rtmr_supported(&mut self) -> bool {
308 match self.req_rtmr_status() {
309 Ok(_) => true,
310 Err(err) => {
311 println!("error: {}", err);
312 false
313 }
314 }
315 }
316
317 pub fn check_attestation_report_v2_supported(&mut self) -> bool {
320 self.check_rtmr_supported()
321 }
322}