1use crate::{
10 attributes::{ObjectAttributesBuilder, SessionAttributesBuilder},
11 constants::{SessionType, TpmFormatZeroError},
12 error::{TpmFormatZeroResponseCode, TpmResponseCode},
13 handles::{KeyHandle, ObjectHandle, SessionHandle},
14 interface_types::{
15 algorithm::{HashingAlgorithm, PublicAlgorithm},
16 ecc::EccCurve,
17 key_bits::RsaKeyBits,
18 reserved_handles::Hierarchy,
19 },
20 structures::{
21 Auth, CreateKeyResult, Data, Digest, EccPoint, EccScheme, Name, Public, PublicBuilder,
22 PublicEccParametersBuilder, PublicKeyRsa, PublicRsaParametersBuilder, RsaExponent,
23 RsaScheme, SavedTpmContext, Signature, SignatureScheme, SymmetricDefinitionObject,
24 VerifiedTicket,
25 },
26 tcti_ldr::TctiNameConf,
27 utils::{create_restricted_decryption_rsa_public, PublicKey},
28 Context, Error, Result, ReturnCode, WrapperErrorKind as ErrorKind,
29};
30
31use log::error;
32use std::collections::HashMap;
33use std::convert::{AsMut, AsRef, TryFrom, TryInto};
34use zeroize::Zeroize;
35
36mod key_attestation;
37
38pub use key_attestation::MakeCredParams;
39
40#[derive(Debug, Clone, Copy)]
42pub enum KeyParams {
43 Rsa {
44 size: RsaKeyBits,
48 scheme: RsaScheme,
50 pub_exponent: RsaExponent,
56 },
57 Ecc {
58 curve: EccCurve,
60 scheme: EccScheme,
62 },
63}
64
65#[derive(Debug, Clone, Zeroize)]
82#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
83pub struct KeyMaterial {
84 public: PublicKey,
85 private: Vec<u8>,
86}
87
88impl KeyMaterial {
89 pub fn public(&self) -> &PublicKey {
91 &self.public
92 }
93
94 pub fn private(&self) -> &[u8] {
96 &self.private
97 }
98}
99
100#[derive(Debug, Clone)]
108pub struct ObjectWrapper {
109 pub material: KeyMaterial,
110 pub params: KeyParams,
111 pub auth: Option<Auth>,
112}
113
114#[allow(clippy::module_name_repetitions)]
122#[derive(Debug)]
123pub struct TransientKeyContext {
124 context: Context,
125 root_key_handle: KeyHandle,
126}
127
128impl TransientKeyContext {
129 pub fn create_key(
147 &mut self,
148 key_params: KeyParams,
149 auth_size: usize,
150 ) -> Result<(KeyMaterial, Option<Auth>)> {
151 if auth_size > 32 {
152 return Err(Error::local_error(ErrorKind::WrongParamSize));
153 }
154 let key_auth = if auth_size > 0 {
155 self.set_session_attrs()?;
156 let mut random_bytes = vec![0u8; auth_size];
157 getrandom::getrandom(&mut random_bytes).map_err(|_| {
158 log::error!("Failed to obtain a random authvalue for key creation");
159 Error::WrapperError(ErrorKind::InternalError)
160 })?;
161 Some(Auth::from_bytes(random_bytes.as_slice())?)
162 } else {
163 None
164 };
165
166 self.set_session_attrs()?;
167 let CreateKeyResult {
168 out_private,
169 out_public,
170 ..
171 } = self.context.create(
172 self.root_key_handle,
173 TransientKeyContext::get_public_from_params(key_params, None)?,
174 key_auth.clone(),
175 None,
176 None,
177 None,
178 )?;
179
180 let key_material = KeyMaterial {
181 public: out_public.try_into()?,
182 private: out_private.as_bytes().to_vec(),
183 };
184 Ok((key_material, key_auth))
185 }
186
187 pub fn load_external_public_key(
191 &mut self,
192 public_key: PublicKey,
193 params: KeyParams,
194 ) -> Result<KeyMaterial> {
195 let public = TransientKeyContext::get_public_from_params(params, Some(public_key.clone()))?;
196 self.set_session_attrs()?;
197 let key_handle = self.context.load_external(None, public, Hierarchy::Owner)?;
198 self.context.flush_context(key_handle.into())?;
199 Ok(KeyMaterial {
200 public: public_key,
201 private: vec![],
202 })
203 }
204
205 pub fn rsa_encrypt(
212 &mut self,
213 key_material: KeyMaterial,
214 key_params: KeyParams,
215 key_auth: Option<Auth>,
216 message: PublicKeyRsa,
217 label: Option<Data>,
218 ) -> Result<PublicKeyRsa> {
219 let key_handle = self.load_key(key_params, key_material, key_auth)?;
220 let decrypt_scheme = if let KeyParams::Rsa { scheme, .. } = key_params {
221 scheme.try_into()?
222 } else {
223 return Err(Error::local_error(ErrorKind::InvalidParam));
224 };
225
226 self.set_session_attrs()?;
227 let ciphertext = self
228 .context
229 .rsa_encrypt(
230 key_handle,
231 message,
232 decrypt_scheme,
233 label.unwrap_or_default(),
234 )
235 .or_else(|e| {
236 self.context.flush_context(key_handle.into())?;
237 Err(e)
238 })?;
239
240 self.context.flush_context(key_handle.into())?;
241
242 Ok(ciphertext)
243 }
244
245 pub fn rsa_decrypt(
252 &mut self,
253 key_material: KeyMaterial,
254 key_params: KeyParams,
255 key_auth: Option<Auth>,
256 ciphertext: PublicKeyRsa,
257 label: Option<Data>,
258 ) -> Result<PublicKeyRsa> {
259 let key_handle = self.load_key(key_params, key_material, key_auth)?;
260 let decrypt_scheme = if let KeyParams::Rsa { scheme, .. } = key_params {
261 scheme.try_into()?
262 } else {
263 return Err(Error::local_error(ErrorKind::InvalidParam));
264 };
265
266 self.set_session_attrs()?;
267 let plaintext = self
268 .context
269 .rsa_decrypt(
270 key_handle,
271 ciphertext,
272 decrypt_scheme,
273 label.unwrap_or_default(),
274 )
275 .or_else(|e| {
276 self.context.flush_context(key_handle.into())?;
277 Err(e)
278 })?;
279
280 self.context.flush_context(key_handle.into())?;
281
282 Ok(plaintext)
283 }
284
285 pub fn sign(
289 &mut self,
290 key_material: KeyMaterial,
291 key_params: KeyParams,
292 key_auth: Option<Auth>,
293 digest: Digest,
294 ) -> Result<Signature> {
295 let key_handle = self.load_key(key_params, key_material, key_auth)?;
296
297 self.set_session_attrs()?;
298 let signature = self
299 .context
300 .sign(key_handle, digest, SignatureScheme::Null, None)
301 .or_else(|e| {
302 self.context.flush_context(key_handle.into())?;
303 Err(e)
304 })?;
305 self.context.flush_context(key_handle.into())?;
306 Ok(signature)
307 }
308
309 pub fn verify_signature(
317 &mut self,
318 key_material: KeyMaterial,
319 key_params: KeyParams,
320 digest: Digest,
321 signature: Signature,
322 ) -> Result<VerifiedTicket> {
323 let key_handle = self.load_key(key_params, key_material, None)?;
324
325 self.set_session_attrs()?;
326 let verified = self
327 .context
328 .verify_signature(key_handle, digest, signature)
329 .or_else(|e| {
330 self.context.flush_context(key_handle.into())?;
331 Err(e)
332 })?;
333 self.context.flush_context(key_handle.into())?;
334 Ok(verified)
335 }
336
337 pub fn migrate_key_from_ctx(
346 &mut self,
347 context: SavedTpmContext,
348 auth: Option<Auth>,
349 ) -> Result<KeyMaterial> {
350 self.set_session_attrs()?;
351 let key_handle = self.context.context_load(context).map(KeyHandle::from)?;
352 if let Some(key_auth_value) = auth.clone() {
353 self.context
354 .tr_set_auth(key_handle.into(), key_auth_value)
355 .or_else(|e| {
356 self.context.flush_context(key_handle.into())?;
357 Err(e)
358 })?;
359 }
360
361 let (public, _, _) = self.context.read_public(key_handle).or_else(|e| {
362 self.context.flush_context(key_handle.into())?;
363 Err(e)
364 })?;
365 let private = self
366 .context
367 .object_change_auth(
368 key_handle.into(),
369 self.root_key_handle.into(),
370 auth.unwrap_or_default(),
371 )
372 .or_else(|e| {
373 if let Error::TssError(ReturnCode::Tpm(TpmResponseCode::FormatZero(
374 TpmFormatZeroResponseCode::Error(error),
375 ))) = e
376 {
377 if error.error_number() == TpmFormatZeroError::AuthUnavailable {
380 return Ok(Default::default());
381 }
382 }
383 error!("Getting private part of key failed.");
384 self.context.flush_context(key_handle.into())?;
385 Err(e)
386 })?;
387
388 let key_material = KeyMaterial {
389 public: public.try_into()?,
390 private: private.as_bytes().to_vec(),
391 };
392
393 self.context.flush_context(key_handle.into())?;
394 Ok(key_material)
395 }
396
397 pub fn get_root_key_name(&mut self) -> Result<Name> {
399 let obj_handle: ObjectHandle = self.root_key_handle.into();
400 self.context.tr_get_name(obj_handle)
401 }
402
403 fn set_session_attrs(&mut self) -> Result<()> {
408 if let (Some(session), _, _) = self.context.sessions() {
409 let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
410 .with_decrypt(true)
411 .with_encrypt(true)
412 .build();
413 self.context.tr_sess_set_attributes(
414 session,
415 session_attributes,
416 session_attributes_mask,
417 )?;
418 }
419 Ok(())
420 }
421
422 fn get_public_from_params(params: KeyParams, pub_key: Option<PublicKey>) -> Result<Public> {
429 let decrypt_flag = matches!(
430 params,
431 KeyParams::Rsa {
432 scheme: RsaScheme::RsaEs,
433 ..
434 } | KeyParams::Rsa {
435 scheme: RsaScheme::Oaep(..),
436 ..
437 }
438 );
439 let object_attributes = ObjectAttributesBuilder::new()
440 .with_fixed_tpm(true)
441 .with_fixed_parent(true)
442 .with_sensitive_data_origin(true)
443 .with_user_with_auth(true)
444 .with_decrypt(decrypt_flag)
445 .with_sign_encrypt(true)
446 .with_restricted(false)
447 .build()?;
448
449 let mut pub_builder = PublicBuilder::new()
450 .with_public_algorithm(match params {
451 KeyParams::Ecc { .. } => PublicAlgorithm::Ecc,
452 KeyParams::Rsa { .. } => PublicAlgorithm::Rsa,
453 })
454 .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
455 .with_object_attributes(object_attributes);
456 match params {
457 KeyParams::Rsa {
458 size,
459 scheme,
460 pub_exponent,
461 } => {
462 let unique = pub_key
463 .map(|pub_key| {
464 if let PublicKey::Rsa(val) = pub_key {
465 PublicKeyRsa::try_from(val)
466 } else {
467 Err(Error::local_error(ErrorKind::InconsistentParams))
468 }
469 })
470 .transpose()?
471 .unwrap_or_default();
472 pub_builder = pub_builder
473 .with_rsa_parameters(
474 PublicRsaParametersBuilder::new()
475 .with_scheme(match scheme {
476 RsaScheme::RsaSsa { .. } | RsaScheme::RsaPss { .. } => scheme,
477 _ => RsaScheme::Null,
478 })
479 .with_key_bits(size)
480 .with_exponent(pub_exponent)
481 .with_is_signing_key(true)
482 .with_is_decryption_key(decrypt_flag)
483 .with_restricted(false)
484 .build()?,
485 )
486 .with_rsa_unique_identifier(unique);
487 }
488 KeyParams::Ecc { scheme, curve } => {
489 let unique = pub_key
490 .map(|pub_key| {
491 if let PublicKey::Ecc { x, y } = pub_key {
492 Ok(EccPoint::new(x.try_into()?, y.try_into()?))
493 } else {
494 Err(Error::local_error(ErrorKind::InconsistentParams))
495 }
496 })
497 .transpose()?
498 .unwrap_or_default();
499 pub_builder = pub_builder
500 .with_ecc_parameters(
501 PublicEccParametersBuilder::new_unrestricted_signing_key(scheme, curve)
502 .build()?,
503 )
504 .with_ecc_unique_identifier(unique);
505 }
506 }
507 pub_builder.build()
508 }
509
510 fn load_key(
514 &mut self,
515 params: KeyParams,
516 material: KeyMaterial,
517 auth: Option<Auth>,
518 ) -> Result<KeyHandle> {
519 let public = TransientKeyContext::get_public_from_params(params, Some(material.public))?;
520
521 self.set_session_attrs()?;
522 let key_handle = if material.private.is_empty() {
523 self.context.load_external(None, public, Hierarchy::Owner)?
524 } else {
525 self.context
526 .load(self.root_key_handle, material.private.try_into()?, public)?
527 };
528 let key_auth_value = auth.unwrap_or_default();
529 if !key_auth_value.is_empty() {
530 self.context
531 .tr_set_auth(key_handle.into(), key_auth_value)
532 .or_else(|e| {
533 self.context.flush_context(key_handle.into())?;
534 Err(e)
535 })?;
536 }
537 Ok(key_handle)
538 }
539
540 pub fn builder() -> TransientKeyContextBuilder {
542 TransientKeyContextBuilder::new()
543 }
544}
545
546impl AsRef<Context> for TransientKeyContext {
547 fn as_ref(&self) -> &Context {
548 &self.context
549 }
550}
551
552impl AsMut<Context> for TransientKeyContext {
553 fn as_mut(&mut self) -> &mut Context {
554 &mut self.context
555 }
556}
557
558#[derive(Debug)]
569pub struct TransientKeyContextBuilder {
570 tcti_name_conf: TctiNameConf,
571 root_key_size: u16, root_key_auth_size: usize,
573 root_hierarchy: Hierarchy,
574 hierarchy_auth: HashMap<Hierarchy, Vec<u8>>,
575 default_context_cipher: SymmetricDefinitionObject,
576 session_hash_alg: HashingAlgorithm,
577}
578
579impl TransientKeyContextBuilder {
580 pub fn new() -> Self {
582 TransientKeyContextBuilder {
583 tcti_name_conf: TctiNameConf::Device(Default::default()),
584 root_hierarchy: Hierarchy::Owner,
585 root_key_size: 2048,
586 root_key_auth_size: 32,
587 hierarchy_auth: HashMap::new(),
588 default_context_cipher: SymmetricDefinitionObject::AES_256_CFB,
589 session_hash_alg: HashingAlgorithm::Sha256,
590 }
591 }
592
593 pub fn with_tcti(mut self, tcti_name_conf: TctiNameConf) -> Self {
595 self.tcti_name_conf = tcti_name_conf;
596 self
597 }
598
599 pub fn with_hierarchy_auth(mut self, hierarchy: Hierarchy, auth: Vec<u8>) -> Self {
601 let _ = self.hierarchy_auth.insert(hierarchy, auth);
602 self
603 }
604
605 pub fn with_root_hierarchy(mut self, hierarchy: Hierarchy) -> Self {
607 self.root_hierarchy = hierarchy;
608 self
609 }
610
611 pub fn with_root_key_size(mut self, root_key_size: u16) -> Self {
613 self.root_key_size = root_key_size;
614 self
615 }
616
617 pub fn with_root_key_auth_size(mut self, root_key_auth_size: usize) -> Self {
619 self.root_key_auth_size = root_key_auth_size;
620 self
621 }
622
623 pub fn with_default_context_cipher(
629 mut self,
630 default_context_cipher: SymmetricDefinitionObject,
631 ) -> Self {
632 self.default_context_cipher = default_context_cipher;
633 self
634 }
635
636 pub fn with_session_hash_alg(mut self, session_hash_alg: HashingAlgorithm) -> Self {
638 self.session_hash_alg = session_hash_alg;
639 self
640 }
641
642 pub fn build(mut self) -> Result<TransientKeyContext> {
664 if self.root_key_auth_size > 32 {
665 return Err(Error::local_error(ErrorKind::WrongParamSize));
666 }
667
668 let root_key_rsa_key_bits = RsaKeyBits::try_from(self.root_key_size)?;
669
670 let mut context = Context::new(self.tcti_name_conf)?;
671
672 let root_key_auth = if self.root_key_auth_size > 0 {
673 let mut random = vec![0u8; self.root_key_auth_size];
674 getrandom::getrandom(&mut random).map_err(|_| {
675 log::error!("Failed to obtain a random value for root key authentication");
676 Error::WrapperError(ErrorKind::InternalError)
677 })?;
678 Some(Auth::from_bytes(random.as_slice())?)
679 } else {
680 None
681 };
682
683 for (hierarchy, auth) in self.hierarchy_auth.drain() {
684 let auth_hierarchy = Auth::try_from(auth)?;
685 context.tr_set_auth(hierarchy.into(), auth_hierarchy)?;
686 }
687
688 let session = context
689 .start_auth_session(
690 None,
691 None,
692 None,
693 SessionType::Hmac,
694 self.default_context_cipher.into(),
695 self.session_hash_alg,
696 )
697 .and_then(|session| {
698 session.ok_or_else(|| {
699 error!("Received unexpected NONE handle from the TPM");
700 Error::local_error(ErrorKind::WrongValueFromTpm)
701 })
702 })?;
703 let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
704 .with_decrypt(true)
705 .with_encrypt(true)
706 .build();
707 context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)?;
708 context.set_sessions((Some(session), None, None));
709
710 let root_key_handle = context
711 .create_primary(
712 self.root_hierarchy,
713 create_restricted_decryption_rsa_public(
714 self.default_context_cipher,
715 root_key_rsa_key_bits,
716 RsaExponent::ZERO_EXPONENT,
717 )?,
718 root_key_auth,
719 None,
720 None,
721 None,
722 )?
723 .key_handle;
724
725 let new_session_cipher = self.default_context_cipher;
726 let new_session_hashing_algorithm = self.session_hash_alg;
727 let new_session = context.execute_without_session(|ctx| {
728 ctx.start_auth_session(
729 Some(root_key_handle),
730 None,
731 None,
732 SessionType::Hmac,
733 new_session_cipher.into(),
734 new_session_hashing_algorithm,
735 )
736 .and_then(|session| {
737 session.ok_or_else(|| {
738 error!("Received unexpected NONE handle from the TPM");
739 Error::local_error(ErrorKind::WrongValueFromTpm)
740 })
741 })
742 })?;
743 if let (Some(old_session), _, _) = context.sessions() {
744 context.set_sessions((Some(new_session), None, None));
745 context.flush_context(SessionHandle::from(old_session).into())?;
746 }
747 Ok(TransientKeyContext {
748 context,
749 root_key_handle,
750 })
751 }
752}
753
754impl Default for TransientKeyContextBuilder {
755 fn default() -> Self {
756 TransientKeyContextBuilder::new()
757 }
758}