use crate::keywrap::AuthLevel;
use keycache_libsecureenclave_sys::{LibSecureEnclave, sep_buf_t, sep_permissions_t};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::fmt::{Display, Formatter};
use std::io::{Error, ErrorKind};
#[derive(Serialize, Deserialize)]
#[serde(remote = "sep_buf_t")]
#[allow(unused, reason = "serde reference to autogenerated binding")]
#[allow(non_camel_case_types, reason = "reference to autogenerated binding")]
struct sep_buf_t__serdedef {
len: usize,
#[serde(with = "serde_bytes")]
bytes: [u8; 2040],
}
#[derive(Debug, Clone, Copy)]
struct SecureEnclaveError(sep_buf_t);
impl Display for SecureEnclaveError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match str::from_utf8(&self.0.bytes[..self.0.len]) {
Ok(msg) => write!(f, "{msg}"),
Err(_) => write!(f, "<non-utf8 error message>"),
}
}
}
impl std::error::Error for SecureEnclaveError {
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[repr(C)]
struct Metadata {
#[serde(with = "sep_buf_t__serdedef")]
private: sep_buf_t,
#[serde(with = "sep_buf_t__serdedef")]
ephemeral: sep_buf_t,
}
pub fn create(auth_level: AuthLevel) -> Result<Vec<u8>, Error> {
const EPHEMERAL_PERMS: sep_permissions_t = sep_permissions_t::sep_permissions_needs_unlock_once;
let libsecureenclave = unsafe { LibSecureEnclave::load() };
let mut error = SecureEnclaveError(sep_buf_t { len: 0, bytes: [0; _] });
let permissions = match auth_level {
AuthLevel::Unauthenticated => sep_permissions_t::sep_permissions_needs_unlock_once,
AuthLevel::Interactive => sep_permissions_t::sep_permissions_needs_interactive_auth,
AuthLevel::Biometry => sep_permissions_t::sep_permissions_needs_same_biometry,
};
let mut private = sep_buf_t { len: 0, bytes: [0; _] };
let retval = unsafe { (libsecureenclave.sep_p256_generate)(permissions, &mut private, &mut error.0) };
assert_eq!(retval, 0, "failed to generate sep private key");
let mut ephemeral_private = sep_buf_t { len: 0, bytes: [0; _] };
let retval = unsafe { (libsecureenclave.sep_p256_generate)(EPHEMERAL_PERMS, &mut ephemeral_private, &mut error.0) };
assert_eq!(retval, 0, "failed to generate sep private key");
let mut ephemeral = sep_buf_t { len: 0, bytes: [0; _] };
let retval = unsafe { (libsecureenclave.sep_p256_publickey)(&ephemeral_private, &mut ephemeral, &mut error.0) };
assert_eq!(retval, 0, "failed to get public key for sep private key");
let metadata = Metadata { private, ephemeral };
let metadata = serde_asn1_der::to_vec(&metadata).expect("failed to serialize metadata");
Ok(metadata)
}
pub fn unlock(metadata: &[u8], _user_auth: Option<&[u8]>) -> Result<[u8; 32], Error> {
let libsecureenclave = unsafe { LibSecureEnclave::load() };
let mut error = SecureEnclaveError(sep_buf_t { len: 0, bytes: [0; _] });
let Metadata { private, ephemeral } =
serde_asn1_der::from_bytes(metadata).map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
let mut shared_secret = sep_buf_t { len: 0, bytes: [0; _] };
let retval =
unsafe { (libsecureenclave.sep_p256_keyexchange)(&private, &ephemeral, &mut shared_secret, &mut error.0) };
let 0 = retval else {
return Err(Error::new(ErrorKind::PermissionDenied, error));
};
let shared_secret = Sha256::digest(&shared_secret.bytes[..shared_secret.len]);
Ok(shared_secret.into())
}