use super::types::{AttestationReport, AttestationResponse};
use iocuddle::{Group, Ioctl, WriteRead};
use libc::c_void;
use log::*;
use std::io;
const PAGE_SIZE: usize = 4096;
pub enum DcuDeviceIoctl {
GetReport = 0x17,
_Undefined,
}
const DCU: Group = Group::new(b'M');
pub const DCU_GET_REPORT: Ioctl<WriteRead, &MkfdIoctlSecurityAttestationArgs> =
unsafe { DCU.write_read(DcuDeviceIoctl::GetReport as u8) };
#[repr(C)]
pub struct MkfdIoctlSecurityAttestationArgs {
pub dcu_id: u32,
pub cmd_id: u32,
pub version: u32,
pub request_data: *mut c_void,
pub request_size: u64,
pub response_data: *mut c_void,
pub response_size: u64,
pub fw_err: u64,
}
impl MkfdIoctlSecurityAttestationArgs {
pub fn new() -> Self {
Self {
dcu_id: 0,
cmd_id: 0,
version: 1,
request_data: std::ptr::null_mut(),
request_size: 0,
response_data: std::ptr::null_mut(),
response_size: 0,
fw_err: 0,
}
}
pub fn set_attestation_args(&mut self, dcu_id: u32, userdata: [u8; 64]) -> std::io::Result<()> {
unsafe {
self.request_data = libc::malloc(PAGE_SIZE);
if self.request_data.is_null() {
return Err(std::io::Error::last_os_error());
}
libc::memset(self.request_data, 0, PAGE_SIZE);
self.request_size = PAGE_SIZE as u64;
std::ptr::copy_nonoverlapping(
userdata.as_ptr(),
self.request_data as *mut u8,
userdata.len(),
);
trace!("Generated random number for DCU report request");
hex_dump(self.request_data as *const u8, 64);
self.response_data = libc::malloc(PAGE_SIZE);
if self.response_data.is_null() {
libc::free(self.request_data);
return Err(std::io::Error::last_os_error());
}
libc::memset(self.response_data, 0, PAGE_SIZE);
self.response_size = PAGE_SIZE as u64;
self.dcu_id = dcu_id;
Ok(())
}
}
pub unsafe fn free_buffers(&mut self) {
if !self.request_data.is_null() {
libc::free(self.request_data);
self.request_data = std::ptr::null_mut();
}
if !self.response_data.is_null() {
libc::free(self.response_data);
self.response_data = std::ptr::null_mut();
}
}
pub fn extract_report(&mut self) -> Result<Option<AttestationReport>, io::Error> {
unsafe {
if let Some(response) = AttestationResponse::from_raw(self.response_data) {
return Ok(Some(response.report.clone()));
}
}
Ok(None)
}
}
impl Default for MkfdIoctlSecurityAttestationArgs {
fn default() -> Self {
Self::new()
}
}
impl Drop for MkfdIoctlSecurityAttestationArgs {
fn drop(&mut self) {
unsafe { self.free_buffers() }
}
}
fn hex_dump(data: *const u8, len: usize) {
let mut output = String::new();
for i in 0..len {
unsafe {
output.push_str(&format!("{:02x} ", *data.add(i)));
}
if (i + 1) % 16 == 0 {
output.push('\n');
}
}
trace!("Memory dump:\n{}", output);
}