1use crate::{
10 attributes::{ObjectAttributesBuilder, SessionAttributesBuilder},
11 constants::{tss::*, SessionType, Tss2ResponseCodeKind},
12 handles::{KeyHandle, ObjectHandle, SessionHandle},
13 interface_types::{
14 algorithm::{HashingAlgorithm, PublicAlgorithm},
15 ecc::EccCurve,
16 key_bits::RsaKeyBits,
17 resource_handles::Hierarchy,
18 },
19 structures::{
20 Auth, CreateKeyResult, Data, Digest, EccPoint, EccScheme, Name, Public, PublicBuilder,
21 PublicEccParametersBuilder, PublicKeyRsa, PublicRsaParametersBuilder, RsaExponent,
22 RsaScheme, Signature, SignatureScheme, SymmetricDefinitionObject, VerifiedTicket,
23 },
24 tcti_ldr::TctiNameConf,
25 tss2_esys::*,
26 utils::{create_restricted_decryption_rsa_public, PublicKey, TpmsContext},
27 Context, Error, Result, WrapperErrorKind as ErrorKind,
28};
29
30use log::error;
31use serde::{Deserialize, Serialize};
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, Serialize, Deserialize, Clone, Zeroize)]
78pub struct KeyMaterial {
79 public: PublicKey,
80 private: Vec<u8>,
81}
82
83impl KeyMaterial {
84 pub fn public(&self) -> &PublicKey {
86 &self.public
87 }
88
89 pub fn private(&self) -> &[u8] {
91 &self.private
92 }
93}
94
95#[derive(Debug, Clone)]
101pub struct ObjectWrapper {
102 pub material: KeyMaterial,
103 pub params: KeyParams,
104 pub auth: Option<Auth>,
105}
106
107#[allow(clippy::module_name_repetitions)]
115#[derive(Debug)]
116pub struct TransientKeyContext {
117 context: Context,
118 root_key_handle: KeyHandle,
119}
120
121impl TransientKeyContext {
122 pub fn create_key(
140 &mut self,
141 key_params: KeyParams,
142 auth_size: usize,
143 ) -> Result<(KeyMaterial, Option<Auth>)> {
144 if auth_size > 32 {
145 return Err(Error::local_error(ErrorKind::WrongParamSize));
146 }
147 let key_auth = if auth_size > 0 {
148 self.set_session_attrs()?;
149 let mut random_bytes = vec![0u8; auth_size];
150 getrandom::getrandom(&mut random_bytes).map_err(|_| {
151 log::error!("Failed to obtain a random authvalue for key creation");
152 Error::WrapperError(ErrorKind::InternalError)
153 })?;
154 Some(Auth::try_from(random_bytes)?)
155 } else {
156 None
157 };
158
159 self.set_session_attrs()?;
160 let CreateKeyResult {
161 out_private,
162 out_public,
163 ..
164 } = self.context.create(
165 self.root_key_handle,
166 TransientKeyContext::get_public_from_params(key_params, None)?,
167 key_auth.clone(),
168 None,
169 None,
170 None,
171 )?;
172
173 let key_material = KeyMaterial {
174 public: out_public.try_into()?,
175 private: out_private.value().to_vec(),
176 };
177 Ok((key_material, key_auth))
178 }
179
180 pub fn load_external_public_key(
184 &mut self,
185 public_key: PublicKey,
186 params: KeyParams,
187 ) -> Result<KeyMaterial> {
188 let public = TransientKeyContext::get_public_from_params(params, Some(public_key.clone()))?;
189 self.set_session_attrs()?;
190 let key_handle = self
191 .context
192 .load_external_public(public, Hierarchy::Owner)?;
193 self.context.flush_context(key_handle.into())?;
194 Ok(KeyMaterial {
195 public: public_key,
196 private: vec![],
197 })
198 }
199
200 pub fn rsa_encrypt(
207 &mut self,
208 key_material: KeyMaterial,
209 key_params: KeyParams,
210 key_auth: Option<Auth>,
211 message: PublicKeyRsa,
212 label: Option<Data>,
213 ) -> Result<PublicKeyRsa> {
214 let key_handle = self.load_key(key_params, key_material, key_auth)?;
215 let decrypt_scheme = if let KeyParams::Rsa { scheme, .. } = key_params {
216 scheme.try_into()?
217 } else {
218 return Err(Error::local_error(ErrorKind::InvalidParam));
219 };
220
221 self.set_session_attrs()?;
222 let ciphertext = self
223 .context
224 .rsa_encrypt(
225 key_handle,
226 message,
227 decrypt_scheme,
228 label.unwrap_or_default(),
229 )
230 .or_else(|e| {
231 self.context.flush_context(key_handle.into())?;
232 Err(e)
233 })?;
234
235 self.context.flush_context(key_handle.into())?;
236
237 Ok(ciphertext)
238 }
239
240 pub fn rsa_decrypt(
247 &mut self,
248 key_material: KeyMaterial,
249 key_params: KeyParams,
250 key_auth: Option<Auth>,
251 ciphertext: PublicKeyRsa,
252 label: Option<Data>,
253 ) -> Result<PublicKeyRsa> {
254 let key_handle = self.load_key(key_params, key_material, key_auth)?;
255 let decrypt_scheme = if let KeyParams::Rsa { scheme, .. } = key_params {
256 scheme.try_into()?
257 } else {
258 return Err(Error::local_error(ErrorKind::InvalidParam));
259 };
260
261 self.set_session_attrs()?;
262 let plaintext = self
263 .context
264 .rsa_decrypt(
265 key_handle,
266 ciphertext,
267 decrypt_scheme,
268 label.unwrap_or_default(),
269 )
270 .or_else(|e| {
271 self.context.flush_context(key_handle.into())?;
272 Err(e)
273 })?;
274
275 self.context.flush_context(key_handle.into())?;
276
277 Ok(plaintext)
278 }
279
280 pub fn sign(
284 &mut self,
285 key_material: KeyMaterial,
286 key_params: KeyParams,
287 key_auth: Option<Auth>,
288 digest: Digest,
289 ) -> Result<Signature> {
290 let key_handle = self.load_key(key_params, key_material, key_auth)?;
291
292 let validation = TPMT_TK_HASHCHECK {
293 tag: TPM2_ST_HASHCHECK,
294 hierarchy: TPM2_RH_NULL,
295 digest: Default::default(),
296 };
297 self.set_session_attrs()?;
298 let signature = self
299 .context
300 .sign(
301 key_handle,
302 digest,
303 SignatureScheme::Null,
304 validation.try_into()?,
305 )
306 .or_else(|e| {
307 self.context.flush_context(key_handle.into())?;
308 Err(e)
309 })?;
310 self.context.flush_context(key_handle.into())?;
311 Ok(signature)
312 }
313
314 pub fn verify_signature(
322 &mut self,
323 key_material: KeyMaterial,
324 key_params: KeyParams,
325 digest: Digest,
326 signature: Signature,
327 ) -> Result<VerifiedTicket> {
328 let key_handle = self.load_key(key_params, key_material, None)?;
329
330 self.set_session_attrs()?;
331 let verified = self
332 .context
333 .verify_signature(key_handle, digest, signature)
334 .or_else(|e| {
335 self.context.flush_context(key_handle.into())?;
336 Err(e)
337 })?;
338 self.context.flush_context(key_handle.into())?;
339 Ok(verified)
340 }
341
342 pub fn migrate_key_from_ctx(
351 &mut self,
352 context: TpmsContext,
353 auth: Option<Auth>,
354 ) -> Result<KeyMaterial> {
355 self.set_session_attrs()?;
356 let key_handle = self.context.context_load(context).map(KeyHandle::from)?;
357 if let Some(key_auth_value) = auth.clone() {
358 self.context
359 .tr_set_auth(key_handle.into(), key_auth_value)
360 .or_else(|e| {
361 self.context.flush_context(key_handle.into())?;
362 Err(e)
363 })?;
364 }
365
366 let (public, _, _) = self.context.read_public(key_handle).or_else(|e| {
367 self.context.flush_context(key_handle.into())?;
368 Err(e)
369 })?;
370 let private = self
371 .context
372 .object_change_auth(
373 key_handle.into(),
374 self.root_key_handle.into(),
375 auth.unwrap_or_default(),
376 )
377 .or_else(|e| {
378 if let Error::Tss2Error(resp_code) = e {
379 if resp_code.kind() == Some(Tss2ResponseCodeKind::AuthUnavailable) {
382 return Ok(Default::default());
383 }
384 }
385 error!("Getting private part of key failed.");
386 self.context.flush_context(key_handle.into())?;
387 Err(e)
388 })?;
389
390 let key_material = KeyMaterial {
391 public: public.try_into()?,
392 private: private.value().to_vec(),
393 };
394
395 self.context.flush_context(key_handle.into())?;
396 Ok(key_material)
397 }
398
399 pub fn get_root_key_name(&mut self) -> Result<Name> {
401 let obj_handle: ObjectHandle = self.root_key_handle.into();
402 self.context.tr_get_name(obj_handle)
403 }
404
405 fn set_session_attrs(&mut self) -> Result<()> {
410 if let (Some(session), _, _) = self.context.sessions() {
411 let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
412 .with_decrypt(true)
413 .with_encrypt(true)
414 .build();
415 self.context.tr_sess_set_attributes(
416 session,
417 session_attributes,
418 session_attributes_mask,
419 )?;
420 }
421 Ok(())
422 }
423
424 fn get_public_from_params(params: KeyParams, pub_key: Option<PublicKey>) -> Result<Public> {
431 let decrypt_flag = matches!(
432 params,
433 KeyParams::Rsa {
434 scheme: RsaScheme::RsaEs,
435 ..
436 } | KeyParams::Rsa {
437 scheme: RsaScheme::Oaep(..),
438 ..
439 }
440 );
441 let object_attributes = ObjectAttributesBuilder::new()
442 .with_fixed_tpm(true)
443 .with_fixed_parent(true)
444 .with_sensitive_data_origin(true)
445 .with_user_with_auth(true)
446 .with_decrypt(decrypt_flag)
447 .with_sign_encrypt(true)
448 .with_restricted(false)
449 .build()?;
450
451 let mut pub_builder = PublicBuilder::new()
452 .with_public_algorithm(match params {
453 KeyParams::Ecc { .. } => PublicAlgorithm::Ecc,
454 KeyParams::Rsa { .. } => PublicAlgorithm::Rsa,
455 })
456 .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
457 .with_object_attributes(object_attributes);
458 match params {
459 KeyParams::Rsa {
460 size,
461 scheme,
462 pub_exponent,
463 } => {
464 let unique = pub_key
465 .map(|pub_key| {
466 if let PublicKey::Rsa(val) = pub_key {
467 PublicKeyRsa::try_from(val)
468 } else {
469 Err(Error::local_error(ErrorKind::InconsistentParams))
470 }
471 })
472 .transpose()?
473 .unwrap_or_default();
474 pub_builder = pub_builder
475 .with_rsa_parameters(
476 PublicRsaParametersBuilder::new()
477 .with_scheme(match scheme {
478 RsaScheme::RsaSsa { .. } | RsaScheme::RsaPss { .. } => scheme,
479 _ => RsaScheme::Null,
480 })
481 .with_key_bits(size)
482 .with_exponent(pub_exponent)
483 .with_is_signing_key(true)
484 .with_is_decryption_key(decrypt_flag)
485 .with_restricted(false)
486 .build()?,
487 )
488 .with_rsa_unique_identifier(unique);
489 }
490 KeyParams::Ecc { scheme, curve } => {
491 let unique = pub_key
492 .map(|pub_key| {
493 if let PublicKey::Ecc { x, y } = pub_key {
494 Ok(EccPoint::new(x.try_into()?, y.try_into()?))
495 } else {
496 Err(Error::local_error(ErrorKind::InconsistentParams))
497 }
498 })
499 .transpose()?
500 .unwrap_or_default();
501 pub_builder = pub_builder
502 .with_ecc_parameters(
503 PublicEccParametersBuilder::new_unrestricted_signing_key(scheme, curve)
504 .build()?,
505 )
506 .with_ecc_unique_identifier(unique);
507 }
508 }
509 pub_builder.build()
510 }
511
512 fn load_key(
516 &mut self,
517 params: KeyParams,
518 material: KeyMaterial,
519 auth: Option<Auth>,
520 ) -> Result<KeyHandle> {
521 let public = TransientKeyContext::get_public_from_params(params, Some(material.public))?;
522
523 self.set_session_attrs()?;
524 let key_handle = if material.private.is_empty() {
525 self.context
526 .load_external_public(public, Hierarchy::Owner)?
527 } else {
528 self.context
529 .load(self.root_key_handle, material.private.try_into()?, public)
530 .map(KeyHandle::from)?
531 };
532 let key_auth_value = auth.unwrap_or_default();
533 if !key_auth_value.is_empty() {
534 self.context
535 .tr_set_auth(key_handle.into(), key_auth_value)
536 .or_else(|e| {
537 self.context.flush_context(key_handle.into())?;
538 Err(e)
539 })?;
540 }
541 Ok(key_handle)
542 }
543
544 pub fn builder() -> TransientKeyContextBuilder {
546 TransientKeyContextBuilder::new()
547 }
548}
549
550impl AsRef<Context> for TransientKeyContext {
551 fn as_ref(&self) -> &Context {
552 &self.context
553 }
554}
555
556impl AsMut<Context> for TransientKeyContext {
557 fn as_mut(&mut self) -> &mut Context {
558 &mut self.context
559 }
560}
561
562#[derive(Debug)]
573pub struct TransientKeyContextBuilder {
574 tcti_name_conf: TctiNameConf,
575 root_key_size: u16, root_key_auth_size: usize,
577 root_hierarchy: Hierarchy,
578 hierarchy_auth: HashMap<Hierarchy, Vec<u8>>,
579 default_context_cipher: SymmetricDefinitionObject,
580 session_hash_alg: HashingAlgorithm,
581}
582
583impl TransientKeyContextBuilder {
584 pub fn new() -> Self {
586 TransientKeyContextBuilder {
587 tcti_name_conf: TctiNameConf::Device(Default::default()),
588 root_hierarchy: Hierarchy::Owner,
589 root_key_size: 2048,
590 root_key_auth_size: 32,
591 hierarchy_auth: HashMap::new(),
592 default_context_cipher: SymmetricDefinitionObject::AES_256_CFB,
593 session_hash_alg: HashingAlgorithm::Sha256,
594 }
595 }
596
597 pub fn with_tcti(mut self, tcti_name_conf: TctiNameConf) -> Self {
599 self.tcti_name_conf = tcti_name_conf;
600 self
601 }
602
603 pub fn with_hierarchy_auth(mut self, hierarchy: Hierarchy, auth: Vec<u8>) -> Self {
605 let _ = self.hierarchy_auth.insert(hierarchy, auth);
606 self
607 }
608
609 pub fn with_root_hierarchy(mut self, hierarchy: Hierarchy) -> Self {
611 self.root_hierarchy = hierarchy;
612 self
613 }
614
615 pub fn with_root_key_size(mut self, root_key_size: u16) -> Self {
617 self.root_key_size = root_key_size;
618 self
619 }
620
621 pub fn with_root_key_auth_size(mut self, root_key_auth_size: usize) -> Self {
623 self.root_key_auth_size = root_key_auth_size;
624 self
625 }
626
627 pub fn with_default_context_cipher(
633 mut self,
634 default_context_cipher: SymmetricDefinitionObject,
635 ) -> Self {
636 self.default_context_cipher = default_context_cipher;
637 self
638 }
639
640 pub fn with_session_hash_alg(mut self, session_hash_alg: HashingAlgorithm) -> Self {
642 self.session_hash_alg = session_hash_alg;
643 self
644 }
645
646 pub fn build(mut self) -> Result<TransientKeyContext> {
668 if self.root_key_auth_size > 32 {
669 return Err(Error::local_error(ErrorKind::WrongParamSize));
670 }
671
672 let root_key_rsa_key_bits = RsaKeyBits::try_from(self.root_key_size)?;
673
674 let mut context = Context::new(self.tcti_name_conf)?;
675
676 let root_key_auth = if self.root_key_auth_size > 0 {
677 let mut random = vec![0u8; self.root_key_auth_size];
678 getrandom::getrandom(&mut random).map_err(|_| {
679 log::error!("Failed to obtain a random value for root key authentication");
680 Error::WrapperError(ErrorKind::InternalError)
681 })?;
682 Some(Auth::try_from(random)?)
683 } else {
684 None
685 };
686
687 for (hierarchy, auth) in self.hierarchy_auth.drain() {
688 let auth_hierarchy = Auth::try_from(auth)?;
689 context.tr_set_auth(hierarchy.into(), auth_hierarchy)?;
690 }
691
692 let session = context
693 .start_auth_session(
694 None,
695 None,
696 None,
697 SessionType::Hmac,
698 self.default_context_cipher.into(),
699 self.session_hash_alg,
700 )
701 .and_then(|session| {
702 session.ok_or_else(|| {
703 error!("Received unexpected NONE handle from the TPM");
704 Error::local_error(ErrorKind::WrongValueFromTpm)
705 })
706 })?;
707 let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
708 .with_decrypt(true)
709 .with_encrypt(true)
710 .build();
711 context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)?;
712 context.set_sessions((Some(session), None, None));
713
714 let root_key_handle = context
715 .create_primary(
716 self.root_hierarchy,
717 create_restricted_decryption_rsa_public(
718 self.default_context_cipher,
719 root_key_rsa_key_bits,
720 RsaExponent::ZERO_EXPONENT,
721 )?,
722 root_key_auth,
723 None,
724 None,
725 None,
726 )?
727 .key_handle;
728
729 let new_session_cipher = self.default_context_cipher;
730 let new_session_hashing_algorithm = self.session_hash_alg;
731 let new_session = context.execute_without_session(|ctx| {
732 ctx.start_auth_session(
733 Some(root_key_handle),
734 None,
735 None,
736 SessionType::Hmac,
737 new_session_cipher.into(),
738 new_session_hashing_algorithm,
739 )
740 .and_then(|session| {
741 session.ok_or_else(|| {
742 error!("Received unexpected NONE handle from the TPM");
743 Error::local_error(ErrorKind::WrongValueFromTpm)
744 })
745 })
746 })?;
747 if let (Some(old_session), _, _) = context.sessions() {
748 context.set_sessions((Some(new_session), None, None));
749 context.flush_context(SessionHandle::from(old_session).into())?;
750 }
751 Ok(TransientKeyContext {
752 context,
753 root_key_handle,
754 })
755 }
756}
757
758impl Default for TransientKeyContextBuilder {
759 fn default() -> Self {
760 TransientKeyContextBuilder::new()
761 }
762}