1use crate::id::AttestAgent;
2use crate::tpm::{create_identity_provider, HardwareIdentity};
3use anyhow::Result;
4use thiserror::Error;
5use zeroize::Zeroize;
6
7#[derive(Debug, Error)]
8pub enum HardwareError {
9 #[error("No TPM found or initialization failed: {0}")]
10 NoTpmFound(String),
11 #[error("Hardware operation failed: {0}")]
12 OperationFailed(String),
13}
14
15pub struct HardwareKeystore {
16 provider: Box<dyn HardwareIdentity>,
17}
18
19impl std::fmt::Debug for HardwareKeystore {
20 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21 f.debug_struct("HardwareKeystore").finish_non_exhaustive()
22 }
23}
24
25impl HardwareKeystore {
26 pub async fn new() -> Result<Self, HardwareError> {
28 let dev_mode = std::env::var("VEX_DEV_MODE")
29 .map(|v| v == "1")
30 .unwrap_or(false);
31 let allow_fallback = std::env::var("VEX_HARDWARE_ATTESTATION")
32 .map(|v| v != "true")
33 .unwrap_or(true);
34
35 if dev_mode && allow_fallback {
37 return Ok(Self {
38 provider: Box::new(crate::tpm::StubIdentity::default()),
39 });
40 }
41
42 let provider = create_identity_provider(allow_fallback);
43 Ok(Self { provider })
44 }
45
46 pub async fn seal_identity(&self, seed: &[u8; 32]) -> Result<Vec<u8>, HardwareError> {
48 self.provider
49 .seal("identity_seed", seed)
50 .await
51 .map_err(|e| HardwareError::OperationFailed(e.to_string()))
52 }
53
54 pub async fn get_identity(
56 &self,
57 encrypted_blob: &[u8],
58 ) -> Result<AgentIdentity, HardwareError> {
59 let seed = self
60 .provider
61 .unseal(encrypted_blob)
62 .await
63 .map_err(|e| HardwareError::OperationFailed(e.to_string()))?;
64
65 let mut seed_array: [u8; 32] = seed
66 .try_into()
67 .map_err(|_| HardwareError::OperationFailed("Unsealed seed is not 32 bytes".into()))?;
68
69 let agent = crate::id::AttestAgent::from_seed(seed_array);
70 seed_array.zeroize();
71
72 Ok(AgentIdentity {
73 agent_id: agent.to_vex_uuid().to_string(),
74 hardware_id: agent.id.clone(),
75 inner: agent,
76 })
77 }
78}
79
80#[derive(Debug, Clone)]
81pub struct AgentIdentity {
82 pub agent_id: String,
83 pub hardware_id: String,
84 inner: AttestAgent,
85}
86
87impl Default for AgentIdentity {
88 fn default() -> Self {
89 let agent = crate::id::AttestAgent::new();
90 Self {
91 agent_id: agent.to_vex_uuid().to_string(),
92 hardware_id: agent.id.clone(),
93 inner: agent,
94 }
95 }
96}
97
98impl AgentIdentity {
99 pub fn new() -> Self {
101 Self::default()
102 }
103
104 pub fn public_key_hex(&self) -> String {
106 hex::encode(self.inner.signing_key.verifying_key().to_bytes())
107 }
108
109 pub fn sign(&self, message: &[u8]) -> Vec<u8> {
111 self.inner.sign(message).to_bytes().to_vec()
112 }
113
114 pub async fn get_pcrs(
116 &self,
117 indices: &[u32],
118 ) -> Result<std::collections::HashMap<u32, String>> {
119 let provider = crate::tpm::create_identity_provider(true);
120 provider.get_pcrs(indices).await
121 }
122}