1#![deny(clippy::all)]
8#![deny(clippy::pedantic)]
9
10mod ecc;
11mod error;
12mod hash;
13mod rsa;
14mod template;
15
16use openssl::{
17 bn::BigNumContext,
18 ec::{EcGroupRef, EcPointRef, PointConversionForm},
19};
20use rand::{CryptoRng, RngCore};
21use tpm2_protocol::{
22 constant::MAX_DIGEST_SIZE,
23 data::{
24 Tpm2bEccParameter, Tpm2bEncryptedSecret, Tpm2bName, TpmAlgId, TpmaObject, TpmtPublic,
25 TpmtSymDefObject,
26 },
27 TpmMarshal, TpmSized, TpmWriter,
28};
29
30pub use ecc::*;
31pub use error::*;
32pub use hash::*;
33pub use rsa::*;
34pub use template::*;
35
36const UNCOMPRESSED_POINT_TAG: u8 = 0x04;
37
38pub trait TpmExternalKey
40where
41 Self: Sized,
42{
43 fn from_der(bytes: &[u8]) -> Result<(Self, Vec<u8>), TpmCryptoError>;
56
57 fn to_public(
59 &self,
60 hash_alg: TpmAlgId,
61 object_attributes: TpmaObject,
62 symmetric: TpmtSymDefObject,
63 ) -> TpmtPublic;
64
65 fn to_seed(
72 &self,
73 name_alg: TpmHash,
74 rng: &mut (impl RngCore + CryptoRng),
75 ) -> Result<(Vec<u8>, Tpm2bEncryptedSecret), TpmCryptoError>;
76}
77
78pub const KDF_LABEL_DUPLICATE: &str = "DUPLICATE";
79pub const KDF_LABEL_INTEGRITY: &str = "INTEGRITY";
80pub const KDF_LABEL_STORAGE: &str = "STORAGE";
81
82pub fn tpm_make_name(public: &TpmtPublic) -> Result<Tpm2bName, TpmCryptoError> {
93 let name_alg = TpmHash::from(public.name_alg);
94 let alg_bytes = (public.name_alg as u16).to_be_bytes();
95
96 let len = public.len();
97 let mut public_bytes = vec![0u8; len];
98 let mut writer = TpmWriter::new(&mut public_bytes);
99 public
100 .marshal(&mut writer)
101 .map_err(TpmCryptoError::Marshal)?;
102
103 let digest = name_alg.digest(&[&public_bytes])?;
104 let digest_len = digest.len();
105
106 if digest_len > MAX_DIGEST_SIZE {
107 return Err(TpmCryptoError::OperationFailed);
108 }
109
110 let mut final_buf = [0u8; MAX_DIGEST_SIZE + 2];
111 final_buf[..2].copy_from_slice(&alg_bytes);
112 final_buf[2..2 + digest_len].copy_from_slice(&digest);
113
114 Tpm2bName::try_from(&final_buf[..2 + digest_len]).map_err(|_| TpmCryptoError::OperationFailed)
115}
116
117fn tpm_make_point(
127 point: &EcPointRef,
128 group: &EcGroupRef,
129 ctx: &mut BigNumContext,
130) -> Result<(Tpm2bEccParameter, Tpm2bEccParameter), TpmCryptoError> {
131 let pub_bytes = point
132 .to_bytes(group, PointConversionForm::UNCOMPRESSED, ctx)
133 .map_err(|_| TpmCryptoError::OperationFailed)?;
134
135 if pub_bytes.is_empty() || pub_bytes[0] != UNCOMPRESSED_POINT_TAG {
136 return Err(TpmCryptoError::InvalidEccParameters);
137 }
138
139 let coord_len = (pub_bytes.len() - 1) / 2;
140 let x = Tpm2bEccParameter::try_from(&pub_bytes[1..=coord_len])
141 .map_err(|_| TpmCryptoError::OperationFailed)?;
142 let y = Tpm2bEccParameter::try_from(&pub_bytes[1 + coord_len..])
143 .map_err(|_| TpmCryptoError::OperationFailed)?;
144
145 Ok((x, y))
146}