1#![deny(clippy::all)]
8#![deny(clippy::pedantic)]
9
10mod ecc;
11mod error;
12mod hash;
13mod rsa;
14
15use openssl::{
16 bn::BigNumContext,
17 ec::{EcGroupRef, EcPointRef, PointConversionForm},
18};
19use rand::{CryptoRng, RngCore};
20use tpm2_protocol::{
21 constant::MAX_DIGEST_SIZE,
22 data::{
23 Tpm2bEccParameter, Tpm2bEncryptedSecret, Tpm2bName, TpmAlgId, TpmtPublic, TpmtSymDefObject,
24 },
25 TpmMarshal, TpmSized, TpmWriter,
26};
27
28pub use ecc::*;
29pub use error::*;
30pub use hash::*;
31pub use rsa::*;
32
33const UNCOMPRESSED_POINT_TAG: u8 = 0x04;
34
35pub trait PublicKey
37where
38 Self: Sized,
39{
40 fn from_der(bytes: &[u8]) -> Result<(Self, Vec<u8>), Error>;
53
54 fn to_public(&self, hash_alg: TpmAlgId, symmetric: TpmtSymDefObject) -> TpmtPublic;
56
57 fn to_seed(
64 &self,
65 name_alg: Hash,
66 rng: &mut (impl RngCore + CryptoRng),
67 ) -> Result<(Vec<u8>, Tpm2bEncryptedSecret), Error>;
68}
69
70pub const KDF_LABEL_DUPLICATE: &str = "DUPLICATE";
71pub const KDF_LABEL_INTEGRITY: &str = "INTEGRITY";
72pub const KDF_LABEL_STORAGE: &str = "STORAGE";
73
74pub fn tpm_make_name(public: &TpmtPublic) -> Result<Tpm2bName, Error> {
85 let name_alg = Hash::from(public.name_alg);
86 let alg_bytes = (public.name_alg as u16).to_be_bytes();
87
88 let len = public.len();
89 let mut public_bytes = vec![0u8; len];
90 let mut writer = TpmWriter::new(&mut public_bytes);
91 public
92 .marshal(&mut writer)
93 .map_err(|_| Error::OperationFailed)?;
94
95 let digest = name_alg.digest(&[&public_bytes])?;
96 let digest_len = digest.len();
97
98 let mut final_buf = [0u8; MAX_DIGEST_SIZE + 2];
99 final_buf[..2].copy_from_slice(&alg_bytes);
100 final_buf[2..2 + digest_len].copy_from_slice(&digest);
101
102 Tpm2bName::try_from(&final_buf[..2 + digest_len]).map_err(|_| Error::OperationFailed)
103}
104
105fn tpm_make_point(
115 point: &EcPointRef,
116 group: &EcGroupRef,
117 ctx: &mut BigNumContext,
118) -> Result<(Tpm2bEccParameter, Tpm2bEccParameter), Error> {
119 let pub_bytes = point
120 .to_bytes(group, PointConversionForm::UNCOMPRESSED, ctx)
121 .map_err(|_| Error::OperationFailed)?;
122
123 if pub_bytes.is_empty() || pub_bytes[0] != UNCOMPRESSED_POINT_TAG {
124 return Err(Error::InvalidEccParameters);
125 }
126
127 let coord_len = (pub_bytes.len() - 1) / 2;
128 let x = Tpm2bEccParameter::try_from(&pub_bytes[1..=coord_len])
129 .map_err(|_| Error::OperationFailed)?;
130 let y = Tpm2bEccParameter::try_from(&pub_bytes[1 + coord_len..])
131 .map_err(|_| Error::OperationFailed)?;
132
133 Ok((x, y))
134}