Skip to main content

csv_rs/api/guest/
mod.rs

1// Copyright (C) Hygon Info Technologies Ltd.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6use 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
17/// A handle to the CSV guest device.
18pub struct CsvGuest(File);
19
20impl CsvGuest {
21    /// Generate a handle to the CSV guest platform via `/dev/csv-guest`.
22    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    /// Requests an legacy attestation report (i.e. AttestationReportV1) from
28    /// the HYGON Secure Processor.
29    ///
30    /// Hygon CSV1,CSV2 only support legacy attestation report.
31    /// Hygon CSV3 supports legacy attestation report, and supports extended
32    /// attestation report (i.e. AttestationReportV2) if the firmware has a
33    /// build version >= 2337.
34    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        // Convert ReportReq to bytes
54        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        // Copy bytes from report_request to report_response
65        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    /// Requests an extended attestation report (i.e. AttestationReportV2) from
81    /// the HYGON Secure Processor.
82    ///
83    /// Hygon CSV1,CSV2 only support legacy attestation report.
84    /// Hygon CSV3 supports legacy attestation report, and supports extended
85    /// attestation report if the firmware has a build version >= 2337.
86    ///
87    /// If extended attestation report is not supported, then request legacy
88    /// attestation report.
89    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            // If flags is 0, generate AttestationReportV1.
99            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            // Convert ReportReqExt to bytes
116            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            // Copy bytes from report_request_ext to report_response_ext
127            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    /// Request rtmr_status
146    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    /// Request rtmr_start
183    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    /// Request rtmr_read
223    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    /// Request rtmr_extend
265    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    /// Query if the rtmr is supported.
306    /// The rtmr_status request will succeed when rtmr is supported.
307    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    /// Query if AttestationReportV2 is supported. It's supported when rtmr is
318    /// supported.
319    pub fn check_attestation_report_v2_supported(&mut self) -> bool {
320        self.check_rtmr_supported()
321    }
322}