use core::slice;
use json::{self, JsonValue};
use std::{
ffi::{c_char, CStr},
fmt::Display,
num::NonZeroUsize,
os::raw::c_void,
ptr,
sync::RwLock,
};
use crate::fapi_sys::{
self,
constants::{self, TSS2_RC_SUCCESS},
FAPI_CONTEXT, TPM2_RC, TSS2_RC,
};
use crate::marshal::u64_from_be;
use crate::memory::{cond_out, cond_ptr, opt_to_len, opt_to_ptr, ptr_to_cstr_vec, ptr_to_opt_cstr, CStringHolder, FapiMemoryHolder};
use crate::{
callback::{ActnCallback, AuthCallback, BranCallback, SignCallback},
locking::LockGuard,
};
use crate::{flags::flags_to_string, BaseErrorCode, BlobType, ErrorCode, InternalError, KeyFlags, NvFlags, PaddingFlags, QuoteFlags, SealFlags};
const ERR_NO_RESULT_DATA: ErrorCode = ErrorCode::InternalError(InternalError::NoResultData);
const ERR_INVALID_ARGUMENTS: ErrorCode = ErrorCode::InternalError(InternalError::InvalidArguments);
type TctiOpaqueContextBlob = *mut [u8; 0];
type TpmBlobs = (Option<Vec<u8>>, Option<Vec<u8>>, Option<JsonValue>);
type SignResult = (Vec<u8>, Option<String>, Option<String>);
type QuoteResult = (JsonValue, Vec<u8>, Option<JsonValue>, Option<String>);
#[derive(Debug)]
pub struct FapiContext {
native_holder: NativeContextHolder,
callback_auth: Option<Box<AuthCallback>>,
callback_sign: Option<Box<SignCallback>>,
callback_bran: Option<Box<BranCallback>>,
callback_actn: Option<Box<ActnCallback>>,
}
#[derive(Debug)]
pub struct NativeContextHolder {
native_context: *mut FAPI_CONTEXT,
}
static FAPI_CALL_RWLOCK: RwLock<()> = RwLock::new(());
macro_rules! mk_fapi_rc {
($error:ident) => {
constants::TSS2_FEATURE_RC_LAYER | constants::$error
};
}
macro_rules! fail_if_empty {
($slice:ident) => {
if <[_]>::is_empty($slice) {
return Err(ERR_INVALID_ARGUMENTS);
}
};
($slice:ident, $($next_slice:ident),+) => {
fail_if_empty!($slice);
fail_if_empty!($($next_slice),+)
}
}
macro_rules! fail_if_opt_empty {
($opt_slice:ident) => {
if let Some(slice) = $opt_slice.as_ref() {
fail_if_empty!(slice);
}
};
($opt_slice:ident, $($next_opt_slice:ident),+) => {
fail_if_opt_empty!($opt_slice);
fail_if_opt_empty!($($next_opt_slice),+)
}
}
fn create_result_from_retval(error_code: TPM2_RC) -> Result<(), ErrorCode> {
match error_code {
TSS2_RC_SUCCESS => Ok(()),
_ => Err(ErrorCode::from_raw(error_code)),
}
}
impl FapiContext {
pub fn new() -> Result<Self, ErrorCode> {
let mut native_context: *mut FAPI_CONTEXT = ptr::null_mut();
create_result_from_retval(unsafe { fapi_sys::Fapi_Initialize(&mut native_context, ptr::null()) }).map(|_| Self {
native_holder: NativeContextHolder::new(native_context),
callback_auth: None,
callback_sign: None,
callback_bran: None,
callback_actn: None,
})
}
pub fn set_auth_callback(&mut self, auth_callback: AuthCallback) -> Result<(), ErrorCode> {
let mut callback_box = Box::new(auth_callback);
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_SetAuthCB(
context,
Some(auth_callback_entrypoint),
callback_box.as_mut() as *mut AuthCallback as *mut c_void,
)
})
.map(|_| {
self.callback_auth = Some(callback_box);
})
}
pub fn set_sign_callback(&mut self, sign_callback: SignCallback) -> Result<(), ErrorCode> {
let mut callback_box = Box::new(sign_callback);
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_SetSignCB(
context,
Some(sign_callback_entrypoint),
callback_box.as_mut() as *mut SignCallback as *mut c_void,
)
})
.map(|_| {
self.callback_sign = Some(callback_box);
})
}
pub fn set_branch_callback(&mut self, bran_callback: BranCallback) -> Result<(), ErrorCode> {
let mut callback_box = Box::new(bran_callback);
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_SetBranchCB(
context,
Some(branch_callback_entrypoint),
callback_box.as_mut() as *mut BranCallback as *mut c_void,
)
})
.map(|_| {
self.callback_bran = Some(callback_box);
})
}
pub fn set_policy_action_callback(&mut self, actn_callback: ActnCallback) -> Result<(), ErrorCode> {
let mut callback_box = Box::new(actn_callback);
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_SetPolicyActionCB(
context,
Some(action_callback_entrypoint),
callback_box.as_mut() as *mut ActnCallback as *mut c_void,
)
})
.map(|_| {
self.callback_actn = Some(callback_box);
})
}
pub fn provision(&mut self, auth_eh: Option<&str>, auth_sh: Option<&str>, auth_lo: Option<&str>) -> Result<(), ErrorCode> {
let cstr_eh = CStringHolder::try_from(auth_eh)?;
let cstr_sh = CStringHolder::try_from(auth_sh)?;
let cstr_lo = CStringHolder::try_from(auth_lo)?;
self.fapi_call(true, |context| unsafe {
fapi_sys::Fapi_Provision(context, cstr_eh.as_ptr(), cstr_sh.as_ptr(), cstr_lo.as_ptr())
})
}
pub fn get_info(&mut self) -> Result<JsonValue, ErrorCode> {
let mut tpm_info: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe { fapi_sys::Fapi_GetInfo(context, &mut tpm_info) })
.and_then(|_| FapiMemoryHolder::from_str(tpm_info).to_string().ok_or(ERR_NO_RESULT_DATA))
.and_then(|info_data| json::parse(&info_data[..]).map_err(|_error| ERR_NO_RESULT_DATA))
}
pub fn get_random(&mut self, length: NonZeroUsize) -> Result<Vec<u8>, ErrorCode> {
let mut data_ptr: *mut u8 = ptr::null_mut();
self.fapi_call(false, |context| unsafe { fapi_sys::Fapi_GetRandom(context, length.into(), &mut data_ptr) })
.and_then(|_| FapiMemoryHolder::from_raw(data_ptr, length.into()).to_vec().ok_or(ERR_NO_RESULT_DATA))
}
pub fn create_key(&mut self, key_path: &str, key_type: Option<&[KeyFlags]>, pol_path: Option<&str>, auth_val: Option<&str>) -> Result<(), ErrorCode> {
fail_if_opt_empty!(key_type);
let cstr_path = CStringHolder::try_from(key_path)?;
let cstr_type = CStringHolder::try_from(flags_to_string(key_type)?)?;
let cstr_poli = CStringHolder::try_from(pol_path)?;
let cstr_auth = CStringHolder::try_from(auth_val)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_CreateKey(context, cstr_path.as_ptr(), cstr_type.as_ptr(), cstr_poli.as_ptr(), cstr_auth.as_ptr())
})
}
pub fn import(&mut self, path: &str, data: &JsonValue) -> Result<(), ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let cstr_data = CStringHolder::try_from(data)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_Import(context, cstr_path.as_ptr(), cstr_data.as_ptr())
})
}
pub fn export_key(&mut self, key_to_duplicate: &str, new_parent_public_key: Option<&str>) -> Result<JsonValue, ErrorCode> {
let cstr_duplicate = CStringHolder::try_from(key_to_duplicate)?;
let cstr_publickey = CStringHolder::try_from(new_parent_public_key)?;
let mut encoded_subtree: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_ExportKey(context, cstr_duplicate.as_ptr(), cstr_publickey.as_ptr(), &mut encoded_subtree)
})
.and_then(|_| FapiMemoryHolder::from_str(encoded_subtree).to_string().ok_or(ERR_NO_RESULT_DATA))
.and_then(|exported_data| json::parse(&exported_data[..]).map_err(|_error| ERR_NO_RESULT_DATA))
}
pub fn export_policy(&mut self, path: &str) -> Result<JsonValue, ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let mut policy: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_ExportPolicy(context, cstr_path.as_ptr(), &mut policy)
})
.and_then(|_| FapiMemoryHolder::from_str(policy).to_string().ok_or(ERR_NO_RESULT_DATA))
.and_then(|exported_data| json::parse(&exported_data[..]).map_err(|_error| ERR_NO_RESULT_DATA))
}
pub fn get_tpm_blobs(&mut self, key_path: &str, get_pubkey: bool, get_privkey: bool, get_policy: bool) -> Result<TpmBlobs, ErrorCode> {
if !(get_pubkey || get_privkey || get_policy) {
return Err(ERR_INVALID_ARGUMENTS);
}
let cstr_path = CStringHolder::try_from(key_path)?;
let mut blob_pub_data: *mut u8 = ptr::null_mut();
let mut blob_pub_size: usize = 0;
let mut blob_sec_data: *mut u8 = ptr::null_mut();
let mut blob_sec_size: usize = 0;
let mut policy_string: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_GetTpmBlobs(
context,
cstr_path.as_ptr(),
cond_out(&mut blob_pub_data, get_pubkey),
cond_ptr(&mut blob_pub_size, get_pubkey),
cond_out(&mut blob_sec_data, get_privkey),
cond_ptr(&mut blob_sec_size, get_privkey),
cond_out(&mut policy_string, get_policy),
)
})
.map(|_| {
(
FapiMemoryHolder::from_raw(blob_pub_data, blob_pub_size).to_vec(),
FapiMemoryHolder::from_raw(blob_sec_data, blob_sec_size).to_vec(),
FapiMemoryHolder::from_str(policy_string).to_json(),
)
})
}
pub fn get_esys_blob(&mut self, path: &str) -> Result<(BlobType, Vec<u8>), ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let mut blob_type: u8 = 0;
let mut blob_data: *mut u8 = ptr::null_mut();
let mut blob_size: usize = 0;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_GetEsysBlob(context, cstr_path.as_ptr(), &mut blob_type, &mut blob_data, &mut blob_size)
})
.and_then(|_| FapiMemoryHolder::from_raw(blob_data, blob_size).to_vec().ok_or(ERR_NO_RESULT_DATA))
.and_then(|esys_blob| {
BlobType::try_from(blob_type)
.map(|type_flag| (type_flag, esys_blob))
.map_err(|_| ERR_NO_RESULT_DATA)
})
}
pub fn create_nv(
&mut self,
nv_path: &str,
nvi_type: Option<&[NvFlags]>,
nvi_size: usize,
pol_path: Option<&str>,
auth_val: Option<&str>,
) -> Result<(), ErrorCode> {
fail_if_opt_empty!(nvi_type);
let cstr_path = CStringHolder::try_from(nv_path)?;
let cstr_type = CStringHolder::try_from(flags_to_string(nvi_type)?)?;
let cstr_poli = CStringHolder::try_from(pol_path)?;
let cstr_auth = CStringHolder::try_from(auth_val)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_CreateNv(
context,
cstr_path.as_ptr(),
cstr_type.as_ptr(),
nvi_size,
cstr_poli.as_ptr(),
cstr_auth.as_ptr(),
)
})
}
pub fn nv_read(&mut self, nv_path: &str, request_log: bool) -> Result<(Vec<u8>, Option<JsonValue>), ErrorCode> {
let cstr_path = CStringHolder::try_from(nv_path)?;
let mut data: *mut u8 = ptr::null_mut();
let mut size: usize = 0;
let mut logs: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_NvRead(context, cstr_path.as_ptr(), &mut data, &mut size, cond_out(&mut logs, request_log))
})
.and_then(|_| FapiMemoryHolder::from_raw(data, size).to_vec().ok_or(ERR_NO_RESULT_DATA))
.map(|result| (result, FapiMemoryHolder::from_str(logs).to_json()))
}
pub fn nv_read_u64(&mut self, nv_path: &str) -> Result<u64, ErrorCode> {
self.nv_read(nv_path, false).map(|data| u64_from_be(&data.0[..]))
}
pub fn nv_write(&mut self, nv_path: &str, data: &[u8]) -> Result<(), ErrorCode> {
fail_if_empty!(data);
let cstr_path = CStringHolder::try_from(nv_path)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_NvWrite(context, cstr_path.as_ptr(), data.as_ptr(), data.len())
})
}
pub fn nv_write_u64(&mut self, nv_path: &str, value: u64) -> Result<(), ErrorCode> {
self.nv_write(nv_path, &value.to_be_bytes()[..])
}
pub fn nv_increment(&mut self, nv_path: &str) -> Result<(), ErrorCode> {
let cstr_path = CStringHolder::try_from(nv_path)?;
self.fapi_call(false, |context| unsafe { fapi_sys::Fapi_NvIncrement(context, cstr_path.as_ptr()) })
}
pub fn nv_set_bits(&mut self, nv_path: &str, bitmap: u64) -> Result<(), ErrorCode> {
let cstr_path = CStringHolder::try_from(nv_path)?;
self.fapi_call(false, |context| unsafe { fapi_sys::Fapi_NvSetBits(context, cstr_path.as_ptr(), bitmap) })
}
pub fn nv_extend(&mut self, nv_path: &str, data: &[u8], log_data: Option<&JsonValue>) -> Result<(), ErrorCode> {
fail_if_empty!(data);
let cstr_path = CStringHolder::try_from(nv_path)?;
let cstr_logs = CStringHolder::try_from(log_data)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_NvExtend(context, cstr_path.as_ptr(), data.as_ptr(), data.len(), cstr_logs.as_ptr())
})
}
pub fn write_authorize_nv(&mut self, nv_path: &str, pol_path: &str) -> Result<(), ErrorCode> {
let cstr_path = CStringHolder::try_from(nv_path)?;
let cstr_poli = CStringHolder::try_from(pol_path)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_WriteAuthorizeNv(context, cstr_path.as_ptr(), cstr_poli.as_ptr())
})
}
pub fn pcr_extend(&mut self, pcr_no: u32, data: &[u8], log_data: Option<&str>) -> Result<(), ErrorCode> {
fail_if_empty!(data);
let cstr_logs = CStringHolder::try_from(log_data)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_PcrExtend(context, pcr_no, data.as_ptr(), data.len(), cstr_logs.as_ptr())
})
}
pub fn pcr_read(&mut self, pcr_no: u32, request_log: bool) -> Result<(Vec<u8>, Option<JsonValue>), ErrorCode> {
let mut pcr_data: *mut u8 = ptr::null_mut();
let mut pcr_size: usize = 0usize;
let mut log_data: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_PcrRead(context, pcr_no, &mut pcr_data, &mut pcr_size, cond_out(&mut log_data, request_log))
})
.and_then(|_| FapiMemoryHolder::from_raw(pcr_data, pcr_size).to_vec().ok_or(ERR_NO_RESULT_DATA))
.map(|result| (result, FapiMemoryHolder::from_str(log_data).to_json()))
}
pub fn quote(
&mut self,
pcr_no: &[u32],
quote_type: Option<&[QuoteFlags]>,
key_path: &str,
qualifying_data: Option<&[u8]>,
request_log: bool,
request_cert: bool,
) -> Result<QuoteResult, ErrorCode> {
fail_if_empty!(pcr_no);
fail_if_opt_empty!(quote_type, qualifying_data);
let cstr_path = CStringHolder::try_from(key_path)?;
let cstr_type = CStringHolder::try_from(flags_to_string(quote_type)?)?;
let mut quote_info: *mut c_char = ptr::null_mut();
let mut signature_data: *mut u8 = ptr::null_mut();
let mut signature_size = 0usize;
let mut pcr_log: *mut c_char = ptr::null_mut();
let mut certificate: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_Quote(
context,
pcr_no.as_ptr() as *mut u32,
pcr_no.len(),
cstr_path.as_ptr(),
cstr_type.as_ptr(),
opt_to_ptr(qualifying_data),
opt_to_len(qualifying_data),
&mut quote_info,
&mut signature_data,
&mut signature_size,
cond_out(&mut pcr_log, request_log),
cond_out(&mut certificate, request_cert),
)
})
.and_then(|_| FapiMemoryHolder::from_str(quote_info).to_json().ok_or(ERR_NO_RESULT_DATA))
.and_then(|info| {
FapiMemoryHolder::from_raw(signature_data, signature_size)
.to_vec()
.map(|data| (info, data))
.ok_or(ERR_NO_RESULT_DATA)
})
.map(|signature| {
(
signature.0,
signature.1,
FapiMemoryHolder::from_str(pcr_log).to_json(),
FapiMemoryHolder::from_str(certificate).to_string(),
)
})
}
pub fn verify_quote(
&mut self,
key_path: &str,
qualifying_data: Option<&[u8]>,
quote_info: &JsonValue,
signature: &[u8],
prc_log: Option<&JsonValue>,
) -> Result<bool, ErrorCode> {
fail_if_empty!(signature);
fail_if_opt_empty!(qualifying_data);
let cstr_path = CStringHolder::try_from(key_path)?;
let cstr_info = CStringHolder::try_from(quote_info)?;
let cstr_logs = CStringHolder::try_from(prc_log)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_VerifyQuote(
context,
cstr_path.as_ptr(),
opt_to_ptr(qualifying_data),
opt_to_len(qualifying_data),
cstr_info.as_ptr(),
signature.as_ptr(),
signature.len(),
cstr_logs.as_ptr(),
)
})
.map(|_| true)
.or_else(|error| match error {
ErrorCode::FapiError(BaseErrorCode::GeneralFailure) => Ok(false),
ErrorCode::FapiError(BaseErrorCode::SignatureVerificationFailed) => Ok(false),
_ => Err(error),
})
}
pub fn encrypt(&mut self, key_path: &str, plaintext: &[u8]) -> Result<Vec<u8>, ErrorCode> {
fail_if_empty!(plaintext);
let cstr_path = CStringHolder::try_from(key_path)?;
let mut ciphertext_data: *mut u8 = ptr::null_mut();
let mut ciphertext_size: usize = 0;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_Encrypt(
context,
cstr_path.as_ptr(),
plaintext.as_ptr(),
plaintext.len(),
&mut ciphertext_data,
&mut ciphertext_size,
)
})
.and_then(|_| FapiMemoryHolder::from_raw(ciphertext_data, ciphertext_size).to_vec().ok_or(ERR_NO_RESULT_DATA))
}
pub fn decrypt(&mut self, key_path: &str, ciphertext: &[u8]) -> Result<Vec<u8>, ErrorCode> {
fail_if_empty!(ciphertext);
let cstr_path = CStringHolder::try_from(key_path)?;
let mut plaintext_data: *mut u8 = ptr::null_mut();
let mut plaintext_size: usize = 0;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_Decrypt(
context,
cstr_path.as_ptr(),
ciphertext.as_ptr(),
ciphertext.len(),
&mut plaintext_data,
&mut plaintext_size,
)
})
.and_then(|_| FapiMemoryHolder::from_raw(plaintext_data, plaintext_size).to_vec().ok_or(ERR_NO_RESULT_DATA))
}
pub fn sign(
&mut self,
key_path: &str,
pad_algo: Option<&[PaddingFlags]>,
digest: &[u8],
get_pubkey: bool,
get_cert: bool,
) -> Result<SignResult, ErrorCode> {
fail_if_empty!(digest);
let cstr_path = CStringHolder::try_from(key_path)?;
let cstr_algo = CStringHolder::try_from(flags_to_string(pad_algo)?)?;
let mut signature_data: *mut u8 = ptr::null_mut();
let mut signature_size: usize = 0;
let mut public_key_pem: *mut c_char = ptr::null_mut();
let mut signer_crt_pem: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_Sign(
context,
cstr_path.as_ptr(),
cstr_algo.as_ptr(),
digest.as_ptr(),
digest.len(),
&mut signature_data,
&mut signature_size,
cond_out(&mut public_key_pem, get_pubkey),
cond_out(&mut signer_crt_pem, get_cert),
)
})
.and_then(|_| FapiMemoryHolder::from_raw(signature_data, signature_size).to_vec().ok_or(ERR_NO_RESULT_DATA))
.map(|signature| {
(
signature,
FapiMemoryHolder::from_str(public_key_pem).to_string(),
FapiMemoryHolder::from_str(signer_crt_pem).to_string(),
)
})
}
pub fn verify_signature(&mut self, key_path: &str, digest: &[u8], signature: &[u8]) -> Result<bool, ErrorCode> {
fail_if_empty!(digest, signature);
let cstr_path = CStringHolder::try_from(key_path)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_VerifySignature(context, cstr_path.as_ptr(), digest.as_ptr(), digest.len(), signature.as_ptr(), signature.len())
})
.map(|_| true)
.or_else(|error| match error {
ErrorCode::FapiError(BaseErrorCode::GeneralFailure) => Ok(false),
ErrorCode::FapiError(BaseErrorCode::SignatureVerificationFailed) => Ok(false),
_ => Err(error),
})
}
pub fn create_seal(
&mut self,
path: &str,
seal_type: Option<&[SealFlags]>,
seal_size: NonZeroUsize,
pol_path: Option<&str>,
auth_val: Option<&str>,
data: Option<&[u8]>,
) -> Result<(), ErrorCode> {
fail_if_opt_empty!(seal_type);
fail_if_opt_empty!(data);
let cstr_path = CStringHolder::try_from(path)?;
let cstr_type = CStringHolder::try_from(flags_to_string(seal_type)?)?;
let cstr_poli = CStringHolder::try_from(pol_path)?;
let cstr_auth = CStringHolder::try_from(auth_val)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_CreateSeal(
context,
cstr_path.as_ptr(),
cstr_type.as_ptr(),
seal_size.get(),
cstr_poli.as_ptr(),
cstr_auth.as_ptr(),
opt_to_ptr(data),
)
})
}
pub fn unseal(&mut self, path: &str) -> Result<Vec<u8>, ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let mut sealed_size: usize = 0;
let mut sealed_data: *mut u8 = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_Unseal(context, cstr_path.as_ptr(), &mut sealed_data, &mut sealed_size)
})
.and_then(|_| FapiMemoryHolder::from_raw(sealed_data, sealed_size).to_vec().ok_or(ERR_NO_RESULT_DATA))
}
pub fn get_certificate(&mut self, path: &str) -> Result<Option<String>, ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let mut cert_data_pem: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_GetCertificate(context, cstr_path.as_ptr(), &mut cert_data_pem)
})
.map(|_| FapiMemoryHolder::from_str(cert_data_pem).to_string())
.or_else(|error| match error {
ErrorCode::FapiError(BaseErrorCode::NoCert) => Ok(None),
_ => Err(error),
})
}
pub fn set_certificate(&mut self, path: &str, cert_data: Option<&str>) -> Result<(), ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let cstr_cert = CStringHolder::try_from(cert_data)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_SetCertificate(context, cstr_path.as_ptr(), cstr_cert.as_ptr())
})
}
pub fn get_platform_certificates(&mut self) -> Result<Option<Vec<u8>>, ErrorCode> {
let mut certificate_size: usize = 0;
let mut certificate_data: *mut u8 = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_GetPlatformCertificates(context, &mut certificate_data, &mut certificate_size)
})
.and_then(|_| {
FapiMemoryHolder::from_raw(certificate_data, certificate_size)
.to_vec()
.ok_or(ERR_NO_RESULT_DATA)
.map(Some)
})
.or_else(|error| match error {
ErrorCode::FapiError(BaseErrorCode::NoCert) => Ok(None),
_ => Err(error),
})
}
pub fn get_description(&mut self, path: &str) -> Result<Option<String>, ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let mut description: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_GetDescription(context, cstr_path.as_ptr(), &mut description)
})
.map(|_| FapiMemoryHolder::from_str(description).to_string())
}
pub fn set_description(&mut self, path: &str, description: Option<&str>) -> Result<(), ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let cstr_desc = CStringHolder::try_from(description)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_SetDescription(context, cstr_path.as_ptr(), cstr_desc.as_ptr())
})
}
pub fn get_app_data(&mut self, path: &str) -> Result<Option<Vec<u8>>, ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let mut app_data_size: usize = 0;
let mut app_data_buff: *mut u8 = ptr::null_mut();
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_GetAppData(context, cstr_path.as_ptr(), &mut app_data_buff, &mut app_data_size)
})
.map(|_| FapiMemoryHolder::from_raw(app_data_buff, app_data_size).to_vec())
}
pub fn set_app_data(&mut self, path: &str, app_data: Option<&[u8]>) -> Result<(), ErrorCode> {
fail_if_opt_empty!(app_data);
let cstr_path = CStringHolder::try_from(path)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_SetAppData(context, cstr_path.as_ptr(), opt_to_ptr(app_data), opt_to_len(app_data))
})
}
pub fn list(&mut self, path: &str) -> Result<Vec<String>, ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let mut list: *mut c_char = ptr::null_mut();
self.fapi_call(false, |context| unsafe { fapi_sys::Fapi_List(context, cstr_path.as_ptr(), &mut list) })
.and_then(|_| {
FapiMemoryHolder::from_str(list)
.to_string()
.map(|str| str.split(':').map(str::to_owned).collect())
.ok_or(ERR_NO_RESULT_DATA)
})
}
pub fn delete(&mut self, path: &str) -> Result<(), ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
self.fapi_call(false, |context| unsafe { fapi_sys::Fapi_Delete(context, cstr_path.as_ptr()) })
}
pub fn change_auth(&mut self, path: &str, auth: Option<&str>) -> Result<(), ErrorCode> {
let cstr_path = CStringHolder::try_from(path)?;
let cstr_auth = CStringHolder::try_from(auth)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_ChangeAuth(context, cstr_path.as_ptr(), cstr_auth.as_ptr())
})
}
pub fn authorize_policy(&mut self, pol_path: &str, key_path: &str, ref_data: Option<&[u8]>) -> Result<(), ErrorCode> {
fail_if_opt_empty!(ref_data);
let cstr_path_pol = CStringHolder::try_from(pol_path)?;
let cstr_path_key = CStringHolder::try_from(key_path)?;
self.fapi_call(false, |context| unsafe {
fapi_sys::Fapi_AuthorizePolicy(
context,
cstr_path_pol.as_ptr(),
cstr_path_key.as_ptr(),
opt_to_ptr(ref_data),
opt_to_len(ref_data),
)
})
}
pub fn get_tcti(&mut self) -> Result<TctiOpaqueContextBlob, ErrorCode> {
let mut tcti: *mut fapi_sys::TSS2_TCTI_CONTEXT = ptr::null_mut();
self.fapi_call(false, |context| unsafe { fapi_sys::Fapi_GetTcti(context, &mut tcti) })
.map(|_| tcti as TctiOpaqueContextBlob)
}
pub fn get_poll_handles(&mut self) -> Result<Vec<()>, ErrorCode> {
todo!("Not implemented yet.");
}
fn fapi_call<F>(&mut self, exclusive: bool, caller: F) -> Result<(), ErrorCode>
where
F: FnOnce(*mut FAPI_CONTEXT) -> TSS2_RC,
{
let error_code = {
let _guard = LockGuard::acquire(&FAPI_CALL_RWLOCK, exclusive);
caller(self.native_holder.get())
};
self.clear_callbacks();
create_result_from_retval(error_code)
}
fn clear_callbacks(&mut self) {
if let Some(cb) = &mut self.callback_auth {
cb.clear_buffer()
}
if let Some(cb) = &mut self.callback_sign {
cb.clear_buffer()
}
}
}
impl Display for FapiContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "FapiContext({:p})", self.native_holder.get())
}
}
impl NativeContextHolder {
pub fn new(native_context: *mut FAPI_CONTEXT) -> Self {
Self { native_context }
}
pub fn get(&self) -> *mut FAPI_CONTEXT {
assert!(!self.native_context.is_null(), "FAPI_CONTEXT is a NULL pointer!");
self.native_context
}
}
impl Drop for NativeContextHolder {
fn drop(&mut self) {
unsafe {
fapi_sys::Fapi_Finalize(&mut self.native_context);
self.native_context = ptr::null_mut();
}
}
}
unsafe impl Send for NativeContextHolder {}
unsafe extern "C" fn auth_callback_entrypoint(
object_path: *const c_char,
description: *const c_char,
auth: *mut *const c_char,
user_data: *mut c_void,
) -> TSS2_RC {
if object_path.is_null() || auth.is_null() || user_data.is_null() {
return mk_fapi_rc!(TSS2_BASE_RC_BAD_VALUE);
}
match (*(user_data as *mut AuthCallback)).invoke(CStr::from_ptr(object_path), ptr_to_opt_cstr(description)) {
Some(auth_value) => {
*auth = auth_value.as_ptr();
TSS2_RC_SUCCESS
}
_ => mk_fapi_rc!(TSS2_BASE_RC_GENERAL_FAILURE),
}
}
unsafe extern "C" fn sign_callback_entrypoint(
object_path: *const c_char,
description: *const c_char,
public_key: *const c_char,
key_hint: *const c_char,
hash_alg: u32,
challenge_data: *const u8,
challenge_size: usize,
signature_data: *mut *const u8,
signature_size: *mut usize,
user_data: *mut c_void,
) -> TSS2_RC {
if object_path.is_null()
|| public_key.is_null()
|| hash_alg == 0u32
|| challenge_data.is_null()
|| challenge_size == 0usize
|| signature_data.is_null()
|| signature_size.is_null()
|| user_data.is_null()
{
return mk_fapi_rc!(TSS2_BASE_RC_BAD_VALUE);
}
match (*(user_data as *mut SignCallback)).invoke(
CStr::from_ptr(object_path),
ptr_to_opt_cstr(description),
CStr::from_ptr(public_key),
ptr_to_opt_cstr(key_hint),
hash_alg,
slice::from_raw_parts(challenge_data, challenge_size),
) {
Some(sign_value) => {
*signature_data = sign_value.as_ptr();
*signature_size = sign_value.len();
TSS2_RC_SUCCESS
}
_ => mk_fapi_rc!(TSS2_BASE_RC_GENERAL_FAILURE),
}
}
unsafe extern "C" fn branch_callback_entrypoint(
object_path: *const c_char,
description: *const c_char,
branch_names: *mut *const c_char,
num_branches: usize,
selected: *mut usize,
user_data: *mut c_void,
) -> TSS2_RC {
if object_path.is_null() || branch_names.is_null() || num_branches == 0usize || selected.is_null() || user_data.is_null() {
return mk_fapi_rc!(TSS2_BASE_RC_BAD_VALUE);
}
match (*(user_data as *mut BranCallback)).invoke(
CStr::from_ptr(object_path),
ptr_to_opt_cstr(description),
&ptr_to_cstr_vec(branch_names, num_branches)[..],
) {
Some(bran_value) => {
*selected = bran_value;
TSS2_RC_SUCCESS
}
_ => mk_fapi_rc!(TSS2_BASE_RC_GENERAL_FAILURE),
}
}
unsafe extern "C" fn action_callback_entrypoint(object_path: *const c_char, action: *const c_char, user_data: *mut c_void) -> TSS2_RC {
if object_path.is_null() || user_data.is_null() {
return mk_fapi_rc!(TSS2_BASE_RC_BAD_VALUE);
}
match (*(user_data as *mut ActnCallback)).invoke(CStr::from_ptr(object_path), ptr_to_opt_cstr(action)) {
true => TSS2_RC_SUCCESS,
_ => mk_fapi_rc!(TSS2_BASE_RC_GENERAL_FAILURE),
}
}