use std::ffi::c_void;
use secapi_sys as ffi;
use crate::{convert_result, DigestAlgorithm, ErrorStatus};
pub fn svp_supported() -> Result<bool, ErrorStatus> {
let result = convert_result(unsafe { ffi::sa_svp_supported() });
match result {
Ok(_) => Ok(true),
Err(err) => {
if err == ErrorStatus::OperationNotSupported {
Ok(false)
} else {
Err(err)
}
}
}
}
pub struct SvpMemory {
memory_ptr: *mut c_void,
size: usize,
}
impl SvpMemory {
pub fn allocate(size: usize) -> Result<Self, ErrorStatus> {
let mut memory_ptr: *mut c_void = std::ptr::null_mut();
let memory_ptr_ptr: *mut *mut c_void = &mut memory_ptr;
convert_result(unsafe { ffi::sa_svp_memory_alloc(memory_ptr_ptr, size) })?;
Ok(Self { memory_ptr, size })
}
}
impl Drop for SvpMemory {
fn drop(&mut self) {
let Self { memory_ptr, .. } = self;
let _ = unsafe { ffi::sa_svp_memory_free(*memory_ptr) };
}
}
pub struct SvpOffset {
pub out_offset: usize,
pub in_offset: usize,
pub length: usize,
}
impl From<SvpOffset> for ffi::sa_svp_offset {
fn from(value: SvpOffset) -> Self {
Self {
out_offset: value.out_offset,
in_offset: value.in_offset,
length: value.length,
}
}
}
pub struct SvpBuffer<'a> {
underlying_svp_memory: Option<&'a SvpMemory>,
buffer_handle: ffi::sa_svp_buffer,
}
impl<'a> SvpBuffer<'a> {
pub fn allocate(size: usize) -> Result<Self, ErrorStatus> {
let mut buffer_handle: ffi::sa_svp_buffer = ffi::INVALID_HANDLE;
convert_result(unsafe { ffi::sa_svp_buffer_alloc(&mut buffer_handle as *mut _, size) })?;
Ok(Self {
underlying_svp_memory: None,
buffer_handle,
})
}
pub fn with_underlying_memory(memory: &'a SvpMemory) -> Result<Self, ErrorStatus> {
let mut buffer_handle: ffi::sa_svp_buffer = ffi::INVALID_HANDLE;
convert_result(unsafe {
ffi::sa_svp_buffer_create(&mut buffer_handle as *mut _, memory.memory_ptr, memory.size)
})?;
Ok(Self {
underlying_svp_memory: Some(memory),
buffer_handle,
})
}
pub fn write(
&mut self,
bytes_to_write: &[u8],
offsets: Vec<SvpOffset>,
) -> Result<(), ErrorStatus> {
let mut ffi_offsets = offsets
.into_iter()
.map(|offset| offset.into())
.collect::<Vec<ffi::sa_svp_offset>>();
convert_result(unsafe {
ffi::sa_svp_buffer_write(
self.buffer_handle,
bytes_to_write.as_ptr() as *const _,
bytes_to_write.len(),
ffi_offsets.as_mut_ptr() as *mut _,
ffi_offsets.len(),
)
})?;
Ok(())
}
pub fn copy(&mut self, source: &SvpBuffer, offsets: Vec<SvpOffset>) -> Result<(), ErrorStatus> {
let mut ffi_offsets = offsets
.into_iter()
.map(|offset| offset.into())
.collect::<Vec<ffi::sa_svp_offset>>();
convert_result(unsafe {
ffi::sa_svp_buffer_copy(
self.buffer_handle,
source.buffer_handle,
ffi_offsets.as_mut_ptr() as *mut _,
ffi_offsets.len(),
)
})?;
Ok(())
}
pub fn check(
&self,
offset: usize,
length: usize,
digest_algorithm: DigestAlgorithm,
hash: &[u8],
) -> Result<bool, ErrorStatus> {
let result = convert_result(unsafe {
ffi::sa_svp_buffer_check(
self.buffer_handle,
offset,
length,
digest_algorithm.into(),
hash.as_ptr() as *const _,
hash.len(),
)
});
match result {
Ok(_) => Ok(true),
Err(err) => {
if err == ErrorStatus::VerificationFailed {
Ok(false)
} else {
Err(err)
}
}
}
}
}
impl Drop for SvpBuffer<'_> {
fn drop(&mut self) {
let Self {
underlying_svp_memory,
buffer_handle,
..
} = self;
match underlying_svp_memory.take() {
Some(svp_memory) => {
let mut svp_memory_ptr = svp_memory.memory_ptr;
let svp_memory_ptr_ptr = &mut svp_memory_ptr as *mut *mut c_void;
let mut size = svp_memory.size;
let _ = unsafe {
ffi::sa_svp_buffer_release(svp_memory_ptr_ptr, &mut size, *buffer_handle)
};
}
None => {
let _ = unsafe { ffi::sa_svp_buffer_free(*buffer_handle) };
}
}
}
}
#[cfg(test)]
mod test {
use crate::{svp::svp_supported, ErrorStatus};
use super::{SvpBuffer, SvpMemory, SvpOffset};
#[test]
fn test_is_svp_supported() -> Result<(), ErrorStatus> {
let supported = svp_supported()?;
assert!(supported);
Ok(())
}
#[test]
fn allocate_svp_memory() -> Result<(), ErrorStatus> {
let _svp_memory = SvpMemory::allocate(128)?;
Ok(())
}
#[test]
fn allocate_buffer() -> Result<(), ErrorStatus> {
let _svp_buffer = SvpBuffer::allocate(128)?;
Ok(())
}
#[test]
fn allocate_buffer_with_underlying_memory() -> Result<(), ErrorStatus> {
let svp_memory = SvpMemory::allocate(128)?;
let _svp_buffer = SvpBuffer::with_underlying_memory(&svp_memory)?;
Ok(())
}
#[test]
fn copy_buffer() -> Result<(), ErrorStatus> {
let mut svp_buffer1 = SvpBuffer::allocate(128)?;
let mut svp_buffer2 = SvpBuffer::allocate(128)?;
svp_buffer2.write(
&[0x01, 0x02, 0x03, 0x04, 0x05],
vec![SvpOffset {
in_offset: 0,
out_offset: 0,
length: 5,
}],
)?;
svp_buffer1.copy(
&svp_buffer2,
vec![SvpOffset {
in_offset: 0,
out_offset: 0,
length: 5,
}],
)?;
Ok(())
}
}