1use super::TpmPublicTemplate;
7use crate::{TpmCryptoError, TpmExternalKey, TpmHash};
8use openssl::{
9 bn::BigNum,
10 hash::MessageDigest,
11 md::Md,
12 pkey::{PKey, Private},
13 pkey_ctx::PkeyCtx,
14 rsa::{Padding, Rsa},
15};
16use rand::{CryptoRng, RngCore};
17use tpm2_protocol::{
18 basic::{TpmUint16, TpmUint32},
19 data::{
20 Tpm2bDigest, Tpm2bEncryptedSecret, Tpm2bPublicKeyRsa, TpmAlgId, TpmsRsaParms,
21 TpmsSchemeHash, TpmtPublic, TpmtRsaScheme, TpmuAsymScheme, TpmuPublicId, TpmuPublicParms,
22 },
23};
24
25#[derive(Debug, Clone)]
27pub struct TpmRsaExternalKey {
28 public_key: Tpm2bPublicKeyRsa,
29 exponent: TpmUint32,
30 key_bits: TpmUint16,
31}
32
33impl TpmRsaExternalKey {
34 #[must_use]
35 pub fn new(public_key: Tpm2bPublicKeyRsa, exponent: TpmUint32, key_bits: TpmUint16) -> Self {
36 Self {
37 public_key,
38 exponent,
39 key_bits,
40 }
41 }
42
43 #[must_use]
45 pub fn public_key(&self) -> &Tpm2bPublicKeyRsa {
46 &self.public_key
47 }
48
49 #[must_use]
51 pub fn exponent(&self) -> TpmUint32 {
52 self.exponent
53 }
54
55 #[must_use]
57 pub fn key_bits(&self) -> TpmUint16 {
58 self.key_bits
59 }
60}
61
62impl TryFrom<&TpmtPublic> for TpmRsaExternalKey {
63 type Error = TpmCryptoError;
64
65 fn try_from(public: &TpmtPublic) -> Result<Self, Self::Error> {
66 if public.object_type != TpmAlgId::Rsa {
67 return Err(TpmCryptoError::InvalidRsaParameters);
68 }
69
70 let params = match &public.parameters {
71 TpmuPublicParms::Rsa(params) => Ok(params),
72 _ => Err(TpmCryptoError::InvalidRsaParameters),
73 }?;
74
75 let n = match &public.unique {
76 TpmuPublicId::Rsa(n) => Ok(*n),
77 _ => Err(TpmCryptoError::InvalidRsaParameters),
78 }?;
79
80 let exponent_u32 = u32::from(params.exponent);
81 let e = if exponent_u32 == 65537 {
82 0
83 } else {
84 exponent_u32
85 };
86
87 Ok(Self {
88 public_key: n,
89 exponent: TpmUint32(e),
90 key_bits: params.key_bits,
91 })
92 }
93}
94
95impl TryFrom<&PKey<Private>> for TpmRsaExternalKey {
96 type Error = TpmCryptoError;
97
98 fn try_from(pkey: &PKey<Private>) -> Result<Self, Self::Error> {
99 let rsa = pkey
100 .rsa()
101 .map_err(|_| TpmCryptoError::InvalidRsaParameters)?;
102 let n = Tpm2bPublicKeyRsa::try_from(rsa.n().to_vec().as_slice())
103 .map_err(|_| TpmCryptoError::InvalidRsaParameters)?;
104
105 let e_bn = rsa.e();
106 if e_bn.is_negative() || e_bn.num_bits() > 32 {
107 return Err(TpmCryptoError::InvalidRsaParameters);
108 }
109 let e_bytes = e_bn.to_vec();
110 let mut e_buf = [0u8; 4];
111 e_buf[4 - e_bytes.len()..].copy_from_slice(&e_bytes);
112 let e = u32::from_be_bytes(e_buf);
113 let e = if e == 65537 { 0 } else { e };
114
115 let key_bits =
116 u16::try_from(rsa.size() * 8).map_err(|_| TpmCryptoError::InvalidRsaParameters)?;
117
118 Ok(Self {
119 public_key: n,
120 exponent: TpmUint32(e),
121 key_bits: TpmUint16(key_bits),
122 })
123 }
124}
125
126impl TpmExternalKey for TpmRsaExternalKey {
127 fn from_der(bytes: &[u8]) -> Result<(Self, Vec<u8>), TpmCryptoError> {
128 let pkey =
129 PKey::private_key_from_der(bytes).map_err(|_| TpmCryptoError::OperationFailed)?;
130 let public_key = TpmRsaExternalKey::try_from(&pkey)?;
131 let rsa = pkey
132 .rsa()
133 .map_err(|_| TpmCryptoError::InvalidRsaParameters)?;
134 let sensitive = rsa.p().ok_or(TpmCryptoError::OperationFailed)?.to_vec();
135 Ok((public_key, sensitive))
136 }
137
138 fn to_public(&self, template: &TpmPublicTemplate) -> TpmtPublic {
139 TpmtPublic {
140 object_type: TpmAlgId::Rsa,
141 name_alg: template.name_alg(),
142 object_attributes: template.object_attributes(),
143 auth_policy: Tpm2bDigest::default(),
144 parameters: TpmuPublicParms::Rsa(TpmsRsaParms {
145 symmetric: template.symmetric(),
146 scheme: TpmtRsaScheme {
147 scheme: TpmAlgId::Oaep,
148 details: TpmuAsymScheme::Hash(TpmsSchemeHash {
149 hash_alg: template.name_alg(),
150 }),
151 },
152 key_bits: self.key_bits,
153 exponent: self.exponent,
154 }),
155 unique: TpmuPublicId::Rsa(self.public_key),
156 }
157 }
158
159 fn to_seed(
160 &self,
161 name_alg: TpmHash,
162 rng: &mut (impl RngCore + CryptoRng),
163 ) -> Result<(Vec<u8>, Tpm2bEncryptedSecret), TpmCryptoError> {
164 let seed_size = name_alg.size();
165 let mut seed = vec![0u8; seed_size];
166 rng.fill_bytes(&mut seed);
167
168 let encrypted_seed_bytes = self.oaep(name_alg, &seed)?;
169
170 let encrypted_seed = Tpm2bEncryptedSecret::try_from(encrypted_seed_bytes.as_slice())
171 .map_err(|_| TpmCryptoError::OutOfMemory)?;
172
173 Ok((seed, encrypted_seed))
174 }
175}
176
177impl TpmRsaExternalKey {
178 fn oaep(&self, name_alg: TpmHash, seed: &[u8]) -> Result<Vec<u8>, TpmCryptoError> {
189 let md = Into::<MessageDigest>::into(name_alg);
190
191 let oaep_md = Md::from_nid(md.type_()).ok_or(TpmCryptoError::OperationFailed)?;
192
193 let n = BigNum::from_slice(self.public_key.as_ref())
194 .map_err(|_| TpmCryptoError::OutOfMemory)?;
195 let exponent_value = match self.exponent.value() {
196 0 => 65537,
197 value => value,
198 };
199 let e = BigNum::from_u32(exponent_value).map_err(|_| TpmCryptoError::OutOfMemory)?;
200 let rsa = Rsa::from_public_components(n, e).map_err(|_| TpmCryptoError::OperationFailed)?;
201 let pkey = PKey::from_rsa(rsa).map_err(|_| TpmCryptoError::OperationFailed)?;
202
203 let mut ctx = PkeyCtx::new(&pkey).map_err(|_| TpmCryptoError::OutOfMemory)?;
204
205 ctx.encrypt_init()
206 .map_err(|_| TpmCryptoError::OperationFailed)?;
207 ctx.set_rsa_padding(Padding::PKCS1_OAEP)
208 .map_err(|_| TpmCryptoError::OperationFailed)?;
209 ctx.set_rsa_oaep_md(oaep_md)
210 .map_err(|_| TpmCryptoError::OperationFailed)?;
211 ctx.set_rsa_mgf1_md(oaep_md)
212 .map_err(|_| TpmCryptoError::OperationFailed)?;
213 ctx.set_rsa_oaep_label(b"DUPLICATE\0")
214 .map_err(|_| TpmCryptoError::OperationFailed)?;
215
216 let mut encrypted_seed = vec![0; pkey.size()];
217 let len = ctx
218 .encrypt(seed, Some(encrypted_seed.as_mut_slice()))
219 .map_err(|_| TpmCryptoError::OperationFailed)?;
220
221 encrypted_seed.truncate(len);
222 Ok(encrypted_seed)
223 }
224}