1#![cfg(target_os = "linux")]
10#![forbid(unsafe_code)]
11
12mod hardware_key_sealing;
13mod igvm_attest;
14mod jwt;
15mod key_protector;
16pub mod runtime_sealing;
17mod secure_key_release;
18mod vmgs;
19
20#[cfg(test)]
21mod test_helpers;
22
23pub use igvm_attest::Error as IgvmAttestError;
24pub use igvm_attest::IgvmAttestRequestHelper;
25pub use igvm_attest::ak_cert::AkCertResponse;
26pub use igvm_attest::ak_cert::parse_metadata as parse_ak_cert_metadata;
27pub use igvm_attest::ak_cert::parse_response as parse_ak_cert_response;
28
29use crate::hardware_key_sealing::HardwareKeySealingError;
30use crate::jwt::JwtError;
31use crate::jwt::JwtHelper;
32use ::vmgs::EncryptionAlgorithm;
33use ::vmgs::GspType;
34use ::vmgs::Vmgs;
35use crypto::rsa::RsaKeyPair;
36use crypto::sha_256::sha_256;
37use cvm_tracing::CVM_ALLOWED;
38use get_protocol::dps_json::GuestStateEncryptionPolicy;
39use guest_emulation_transport::GuestEmulationTransportClient;
40use guest_emulation_transport::api::GspExtendedStatusFlags;
41use guest_emulation_transport::api::GuestStateProtection;
42use guest_emulation_transport::api::GuestStateProtectionById;
43use guid::Guid;
44use hardware_key_sealing::HardwareDerivedKeys;
45use key_protector::GetKeysFromKeyProtectorError;
46use key_protector::KeyProtectorExt as _;
47use mesh::MeshPayload;
48use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::AttestationVmConfig;
49use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::HardwareSealingPolicy;
50use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::VmgsProvisioner;
51use openhcl_attestation_protocol::vmgs::AES_GCM_KEY_LENGTH;
52use openhcl_attestation_protocol::vmgs::AGENT_DATA_MAX_SIZE;
53use openhcl_attestation_protocol::vmgs::HW_KEY_PROTECTOR_CURRENT_VERSION;
54use openhcl_attestation_protocol::vmgs::HardwareKeyProtectorV3;
55use openhcl_attestation_protocol::vmgs::KeyProtector;
56use openhcl_attestation_protocol::vmgs::SecurityProfile;
57use pal_async::local::LocalDriver;
58use secure_key_release::VmgsEncryptionKeys;
59use serde::Deserialize;
60use serde::Serialize;
61use static_assertions::const_assert_eq;
62use std::fmt::Debug;
63use tee_call::KeyDerivationPolicy;
64use tee_call::REPORT_DATA_SIZE;
65use tee_call::TeeCall;
66use tee_call::TeeType;
67use thiserror::Error;
68use zerocopy::FromZeros;
69use zerocopy::IntoBytes;
70
71#[derive(Debug, Error)]
73#[error(transparent)]
74pub struct Error(AttestationErrorInner);
75
76impl<T: Into<AttestationErrorInner>> From<T> for Error {
77 fn from(value: T) -> Self {
78 Self(value.into())
79 }
80}
81
82#[derive(Debug, Error)]
83enum AttestationErrorInner {
84 #[error("read security profile from vmgs")]
85 ReadSecurityProfile(#[source] vmgs::ReadFromVmgsError),
86 #[error("failed to get derived keys")]
87 GetDerivedKeys(#[source] GetDerivedKeysError),
88 #[error("failed to read key protector from vmgs")]
89 ReadKeyProtector(#[source] vmgs::ReadFromVmgsError),
90 #[error("failed to read key protector by id from vmgs")]
91 ReadKeyProtectorById(#[source] vmgs::ReadFromVmgsError),
92 #[error("failed to unlock vmgs data store")]
93 UnlockVmgsDataStore(#[source] UnlockVmgsDataStoreError),
94 #[error("failed to finalize required hardware sealing")]
95 FinalizeHardwareSealing(#[source] FinalizeHardwareSealingError),
96 #[error("failed to read guest secret key from vmgs")]
97 ReadGuestSecretKey(#[source] vmgs::ReadFromVmgsError),
98 #[error("failed to verify VMGS provenance")]
99 Provenance(#[source] ProvenanceError),
100 #[error("failed to get an attestation report")]
101 GetAttestationReport(#[source] tee_call::Error),
102 #[error(
103 "host requested HardwareSealing GSP, but hardware sealing is not available \
104 (tee_available={tee_available}, hardware_sealing_policy={hardware_sealing_policy:?})"
105 )]
106 HardwareSealingRequestedButNotAvailable {
107 tee_available: bool,
108 hardware_sealing_policy: HardwareSealingPolicy,
109 },
110}
111
112#[derive(Debug, Error)]
113enum GetDerivedKeysError {
114 #[error("failed to get ingress/egress keys from the key protector")]
115 GetKeysFromKeyProtector(#[source] GetKeysFromKeyProtectorError),
116 #[error("failed to fetch GSP")]
117 FetchGuestStateProtectionById(
118 #[source] guest_emulation_transport::error::GuestStateProtectionByIdError,
119 ),
120 #[error("GSP By Id required, but no GSP By Id found")]
121 GspByIdRequiredButNotFound,
122 #[error("failed to unseal the ingress key using hardware derived keys")]
123 UnsealIngressKeyUsingHardwareDerivedKeys(#[source] HardwareKeySealingError),
124 #[error("failed to get an ingress key from hardware key protector")]
125 GetIngressKeyFromHardwareKeyProtectorFailed,
126 #[error("failed to get an ingress key from key protector")]
127 GetIngressKeyFromKpFailed,
128 #[error("failed to get an ingress key from guest state protection")]
129 GetIngressKeyFromKGspFailed,
130 #[error("failed to get an ingress key from guest state protection by id")]
131 GetIngressKeyFromKGspByIdFailed,
132 #[error("Encryption cannot be disabled if VMGS was previously encrypted")]
133 DisableVmgsEncryptionFailed,
134 #[error("VMGS encryption is required, but no encryption sources were found")]
135 EncryptionRequiredButNotFound,
136 #[error("failed to seal the egress key using hardware derived keys")]
137 SealEgressKeyUsingHardwareDerivedKeys(#[source] HardwareKeySealingError),
138 #[error("failed to write to `FileId::HW_KEY_PROTECTOR` in vmgs")]
139 VmgsWriteHardwareKeyProtector(#[source] vmgs::WriteToVmgsError),
140 #[error("failed to get derived key by id")]
141 GetDerivedKeyById(#[source] GetDerivedKeysByIdError),
142 #[error("failed to derive an ingress key")]
143 DeriveIngressKey(#[source] crypto::kbkdf::KbkdfError),
144 #[error("failed to derive an egress key")]
145 DeriveEgressKey(#[source] crypto::kbkdf::KbkdfError),
146 #[error("Hardware sealing is required, but not supported")]
147 HardwareSealingRequiredButNotSupported,
148}
149
150#[derive(Debug, Error)]
151enum GetDerivedKeysByIdError {
152 #[error("failed to derive an egress key based on current vm bios guid")]
153 DeriveEgressKeyUsingCurrentVmId(#[source] crypto::kbkdf::KbkdfError),
154 #[error("invalid derived egress key size {key_size}, expected {expected_size}")]
155 InvalidDerivedEgressKeySize {
156 key_size: usize,
157 expected_size: usize,
158 },
159 #[error("failed to derive an ingress key based on key protector Id from vmgs")]
160 DeriveIngressKeyUsingKeyProtectorId(#[source] crypto::kbkdf::KbkdfError),
161 #[error("invalid derived egress key size {key_size}, expected {expected_size}")]
162 InvalidDerivedIngressKeySize {
163 key_size: usize,
164 expected_size: usize,
165 },
166}
167
168#[derive(Debug, Error)]
169enum UnlockVmgsDataStoreError {
170 #[error("failed to unlock vmgs with the existing egress key")]
171 VmgsUnlockUsingExistingEgressKey(#[source] ::vmgs::Error),
172 #[error("failed to unlock vmgs with the existing ingress key")]
173 VmgsUnlockUsingExistingIngressKey(#[source] ::vmgs::Error),
174 #[error("failed to write key protector to vmgs")]
175 WriteKeyProtector(#[source] vmgs::WriteToVmgsError),
176 #[error("failed to write key protector by id to vmgs")]
177 WriteKeyProtectorById(#[source] vmgs::WriteToVmgsError),
178 #[error("failed to update the vmgs encryption key")]
179 UpdateVmgsEncryptionKey(#[source] ::vmgs::Error),
180 #[error("failed to persist all key protectors")]
181 PersistAllKeyProtectors(#[source] PersistAllKeyProtectorsError),
182}
183
184#[derive(Debug, Error)]
185enum PersistAllKeyProtectorsError {
186 #[error("failed to write key protector to vmgs")]
187 KeyProtector(#[source] vmgs::WriteToVmgsError),
188 #[error("failed to write key protector by id to vmgs")]
189 KeyProtectorById(#[source] vmgs::WriteToVmgsError),
190 #[error("failed to write hardware key protector to vmgs")]
191 HardwareKeyProtector(#[source] vmgs::WriteToVmgsError),
192}
193
194#[derive(Debug, Error)]
195enum ProvenanceError {
196 #[error("failed to decode provenance doc")]
197 DecodeProvenanceDoc(#[source] JwtError),
198 #[error("failed to verify JWT signature")]
199 VerifySignature(#[source] JwtError),
200 #[error("invalid signature")]
201 InvalidSignature,
202 #[error("missing leaf certificate subject common name")]
203 MissingLeafCertSubjectName,
204 #[error("invalid root certificate")]
205 InvalidRootCert,
206 #[error("failed to convert VMGSID data")]
207 InvalidVmgsidData(#[source] std::str::Utf8Error),
208 #[error("failed to parse VMGSID seed data")]
209 ParseVmgsidSeedData,
210 #[error("failed to decode VMGSID seed data")]
211 DecodeVmgsidData(#[source] hex::FromHexError),
212 #[error("X509 certificate error")]
213 X509Error(#[source] crypto::x509::X509Error),
214 #[error("SP800-108 KDF error")]
215 KdfError(#[source] crypto::kbkdf::KbkdfError),
216 #[error("failed to parse VMGSID")]
217 ParseVmgsid(#[source] guid::ParseError),
218}
219
220#[derive(Debug, Error)]
222enum FinalizeHardwareSealingError {
223 #[error("no hardware protector was sealed for this unlock attempt")]
224 MissingSealedKey,
225 #[error("active VMGS encryption key is unavailable")]
226 ActiveKey(#[source] ::vmgs::Error),
227 #[error("sealed DEK does not match the active VMGS encryption key")]
228 ActiveKeyMismatch,
229 #[error("failed to flush the hardware protector and VMGS metadata")]
230 Flush(#[source] ::vmgs::Error),
231}
232
233#[derive(Debug)]
235enum LogOpType {
236 BeginDecryptVmgs,
237 DecryptVmgs,
238 ConvertEncryptionType,
239}
240
241const VMGS_KEY_DERIVE_LABEL: &[u8; 7] = b"VMGSKEY";
243
244fn derive_key(
246 key: &[u8],
247 context: &[u8],
248 label: &[u8],
249) -> Result<[u8; AES_GCM_KEY_LENGTH], crypto::kbkdf::KbkdfError> {
250 let output = crypto::kbkdf::kbkdf_hmac(
251 key,
252 context,
253 label,
254 AES_GCM_KEY_LENGTH,
255 crypto::HashAlgorithm::Sha256,
256 )?;
257 Ok(output.try_into().unwrap())
258}
259
260#[derive(Debug)]
261struct Keys {
262 ingress: [u8; AES_GCM_KEY_LENGTH],
263 decrypt_egress: Option<[u8; AES_GCM_KEY_LENGTH]>,
264 encrypt_egress: [u8; AES_GCM_KEY_LENGTH],
265}
266
267#[derive(Clone, Copy)]
269struct KeyProtectorSettings {
270 should_write_kp: bool,
272 use_gsp_by_id: bool,
274 use_hardware_unlock: bool,
276 decrypt_gsp_type: GspType,
278 encrypt_gsp_type: GspType,
280}
281
282struct KeyProtectorById {
284 pub inner: openhcl_attestation_protocol::vmgs::KeyProtectorById,
286 pub found_id: bool,
288}
289
290pub struct HostAttestationSettings {
292 pub refresh_tpm_seeds: bool,
294}
295
296struct DerivedKeyResult {
298 derived_keys: Option<Keys>,
300 key_protector_settings: KeyProtectorSettings,
302 gsp_extended_status_flags: GspExtendedStatusFlags,
304 hardware_key_protector: Option<HardwareKeyProtectorV3>,
306 hardware_key_protector_written: bool,
309}
310
311struct UnlockResult {
313 state_refresh_request: bool,
314 hardware_sealed: bool,
316}
317
318pub struct PlatformAttestationData {
320 pub host_attestation_settings: HostAttestationSettings,
322 pub agent_data: Option<Vec<u8>>,
324 pub guest_secret_key: Option<Vec<u8>>,
326 pub runtime_tcb_floor: Option<runtime_sealing::RuntimeTcbFloor>,
334}
335
336#[derive(Debug, MeshPayload, Copy, Clone, PartialEq, Eq)]
338pub enum AttestationType {
339 Snp,
341 Tdx,
343 Vbs,
345 Cca,
347 Host,
349}
350
351async fn try_unlock_vmgs(
356 get: &GuestEmulationTransportClient,
357 bios_guid: Guid,
358 attestation_vm_config: &AttestationVmConfig,
359 vmgs: &mut Vmgs,
360 tee_call: Option<&dyn TeeCall>,
361 guest_state_encryption_policy: GuestStateEncryptionPolicy,
362 strict_encryption_policy: bool,
363 require_hardware_sealing: bool,
364 agent_data: &mut [u8; AGENT_DATA_MAX_SIZE],
365 key_protector_by_id: &mut KeyProtectorById,
366 boot_tcb_floor: &mut runtime_sealing::BootTcbFloor,
367) -> Result<UnlockResult, (AttestationErrorInner, bool)> {
368 let skr_response = if let Some(tee_call) = tee_call {
369 if !require_hardware_sealing {
370 tracing::info!(CVM_ALLOWED, "Retrieving key-encryption key");
371 secure_key_release::request_vmgs_encryption_keys(
373 get,
374 tee_call,
375 vmgs,
376 attestation_vm_config,
377 agent_data,
378 boot_tcb_floor,
379 )
380 .await
381 } else {
382 tracing::info!(
383 CVM_ALLOWED,
384 "Getting attestation report only for hardware sealing"
385 );
386
387 let report = tee_call
388 .get_attestation_report(&[0; REPORT_DATA_SIZE])
389 .map_err(|e| (AttestationErrorInner::GetAttestationReport(e), false))?;
390 boot_tcb_floor.observe(tee_call, &report);
391
392 Ok(VmgsEncryptionKeys {
393 ingress_rsa_kek: None,
394 wrapped_des_key: None,
395 key_derivation_svn: report.key_derivation_svn,
396 })
397 }
398 } else {
399 tracing::info!(CVM_ALLOWED, "Key-encryption key retrieval not required");
400
401 Ok(VmgsEncryptionKeys::default())
403 };
404
405 let retry = match &skr_response {
406 Ok(_) => false,
407 Err((_, r)) => *r,
408 };
409
410 let skip_hw_unsealing = matches!(
411 &skr_response,
412 Err((
413 secure_key_release::RequestVmgsEncryptionKeysError::ParseIgvmAttestKeyReleaseResponse(
414 igvm_attest::key_release::KeyReleaseError::ParseHeader(
415 igvm_attest::Error::Attestation {
416 skip_hw_unsealing_signal: true,
417 ..
418 },
419 ),
420 ),
421 _,
422 ))
423 );
424
425 let VmgsEncryptionKeys {
426 ingress_rsa_kek,
427 wrapped_des_key,
428 key_derivation_svn,
429 } = match skr_response {
430 Ok(k) => {
431 tracing::info!(CVM_ALLOWED, "Successfully retrieved key-encryption key");
432 k
433 }
434 Err((e, _)) => {
435 tracing::error!(
437 CVM_ALLOWED,
438 error = &e as &dyn std::error::Error,
439 "Failed to retrieve key-encryption key"
440 );
441
442 VmgsEncryptionKeys::default()
443 }
444 };
445
446 let mut key_protector = if !require_hardware_sealing {
447 let dek_minimal_size = if wrapped_des_key.is_some() {
449 key_protector::AES_WRAPPED_AES_KEY_LENGTH
450 } else {
451 key_protector::RSA_WRAPPED_AES_KEY_LENGTH
452 };
453
454 tracing::info!(
456 CVM_ALLOWED,
457 dek_minimal_size = dek_minimal_size,
458 "Reading key protector from VMGS"
459 );
460
461 vmgs::read_key_protector(vmgs, dek_minimal_size)
462 .await
463 .map_err(|e| (AttestationErrorInner::ReadKeyProtector(e), false))?
464 } else {
465 tracing::info!(
466 CVM_ALLOWED,
467 "Hardware sealing is required, skip reading key protector from VMGS"
468 );
469 KeyProtector::new_zeroed()
470 };
471
472 let start_time = std::time::SystemTime::now();
473 let vmgs_encrypted = vmgs.encrypted();
474
475 let mix_measurement = matches!(
479 attestation_vm_config.hardware_sealing_policy,
480 HardwareSealingPolicy::Hash
481 );
482
483 let key_derivation_policy = key_derivation_svn.map(|svn| KeyDerivationPolicy {
484 svn,
485 mix_measurement,
486 });
487
488 tracing::info!(
489 CVM_ALLOWED,
490 key_derivation_policy=?key_derivation_policy,
491 vmgs_encrypted,
492 op_type = ?LogOpType::BeginDecryptVmgs,
493 "Deriving keys"
494 );
495
496 let derived_keys_result = get_derived_keys(
497 get,
498 tee_call,
499 vmgs,
500 &mut key_protector,
501 key_protector_by_id,
502 bios_guid,
503 attestation_vm_config,
504 vmgs_encrypted,
505 ingress_rsa_kek.as_ref(),
506 wrapped_des_key.as_deref(),
507 key_derivation_policy,
508 guest_state_encryption_policy,
509 strict_encryption_policy,
510 require_hardware_sealing,
511 skip_hw_unsealing,
512 )
513 .await
514 .map_err(|e| {
515 tracing::error!(
516 CVM_ALLOWED,
517 op_type = ?LogOpType::DecryptVmgs,
518 success = false,
519 err = &e as &dyn std::error::Error,
520 latency = std::time::SystemTime::now()
521 .duration_since(start_time)
522 .map_or(0, |d| d.as_millis()),
523 "Failed to derive keys"
524 );
525 (AttestationErrorInner::GetDerivedKeys(e), retry)
526 })?;
527
528 tracing::info!("Unlocking VMGS");
529
530 let sealed_egress_key = derived_keys_result
534 .derived_keys
535 .as_ref()
536 .filter(|_| {
537 derived_keys_result.hardware_key_protector.is_some()
538 || derived_keys_result.hardware_key_protector_written
539 })
540 .map(|keys| keys.encrypt_egress);
541
542 if let Err(e) = unlock_vmgs_data_store(
543 vmgs,
544 vmgs_encrypted,
545 &mut key_protector,
546 key_protector_by_id,
547 derived_keys_result.hardware_key_protector,
548 derived_keys_result.derived_keys,
549 derived_keys_result.key_protector_settings,
550 bios_guid,
551 )
552 .await
553 {
554 tracing::error!(
555 CVM_ALLOWED,
556 op_type = ?LogOpType::DecryptVmgs,
557 success = false,
558 err = &e as &dyn std::error::Error,
559 latency = std::time::SystemTime::now()
560 .duration_since(start_time)
561 .map_or(0, |d| d.as_millis()),
562 "Failed to unlock datastore"
563 );
564 get.event_log_fatal(guest_emulation_transport::api::EventLogId::ATTESTATION_FAILED)
565 .await;
566
567 Err((AttestationErrorInner::UnlockVmgsDataStore(e), retry))?;
568 }
569
570 let sealing_required = require_hardware_sealing
573 || derived_keys_result
574 .key_protector_settings
575 .use_hardware_unlock;
576 let hardware_sealed =
577 match finalize_hardware_sealing(vmgs, sealed_egress_key, sealing_required).await {
578 Ok(sealed) => sealed,
579 Err(error) => {
580 tracing::error!(
581 CVM_ALLOWED,
582 op_type = ?LogOpType::DecryptVmgs,
583 success = false,
584 error = &error as &dyn std::error::Error,
585 "Failed to finalize required hardware sealing"
586 );
587 get.event_log_fatal(guest_emulation_transport::api::EventLogId::ATTESTATION_FAILED)
588 .await;
589 return Err((AttestationErrorInner::FinalizeHardwareSealing(error), false));
593 }
594 };
595
596 tracing::info!(
597 CVM_ALLOWED,
598 op_type = ?LogOpType::DecryptVmgs,
599 success = true,
600 decrypt_gsp_type = ?derived_keys_result
601 .key_protector_settings
602 .decrypt_gsp_type,
603 encrypt_gsp_type = ?derived_keys_result
604 .key_protector_settings
605 .encrypt_gsp_type,
606 latency = std::time::SystemTime::now().duration_since(start_time).map_or(0, |d| d.as_millis()),
607 "Unlocked datastore"
608 );
609
610 Ok(UnlockResult {
611 state_refresh_request: derived_keys_result
612 .gsp_extended_status_flags
613 .state_refresh_request(),
614 hardware_sealed,
615 })
616}
617
618async fn finalize_hardware_sealing(
623 vmgs: &mut Vmgs,
624 sealed_egress_key: Option<[u8; AES_GCM_KEY_LENGTH]>,
625 required: bool,
626) -> Result<bool, FinalizeHardwareSealingError> {
627 if sealed_egress_key.is_none() && !required {
628 return Ok(false);
629 }
630 let result = async {
631 let sealed_egress_key =
632 sealed_egress_key.ok_or(FinalizeHardwareSealingError::MissingSealedKey)?;
633 let active = vmgs
636 .active_encryption_key()
637 .map_err(FinalizeHardwareSealingError::ActiveKey)?;
638 if !constant_time_eq::constant_time_eq_32(active, &sealed_egress_key) {
639 return Err(FinalizeHardwareSealingError::ActiveKeyMismatch);
640 }
641 vmgs.flush()
642 .await
643 .map_err(FinalizeHardwareSealingError::Flush)
644 }
645 .await;
646 match result {
647 Ok(()) => Ok(true),
648 Err(error) if required => Err(error),
649 Err(error) => {
650 tracelimit::warn_ratelimited!(
651 CVM_ALLOWED,
652 error = &error as &dyn std::error::Error,
653 "Failed to finalize optional hardware sealing; runtime hardware resealing disabled"
654 );
655 Ok(false)
656 }
657 }
658}
659
660pub async fn initialize_platform_security(
666 get: &GuestEmulationTransportClient,
667 bios_guid: Guid,
668 attestation_vm_config: &AttestationVmConfig,
669 vmgs: &mut Vmgs,
670 tee_call: Option<&dyn TeeCall>,
671 suppress_attestation: bool,
672 driver: LocalDriver,
673 guest_state_encryption_policy: GuestStateEncryptionPolicy,
674 strict_encryption_policy: bool,
675) -> Result<PlatformAttestationData, Error> {
676 const MAXIMUM_RETRY_COUNT: usize = 10;
677 const NO_RETRY_COUNT: usize = 1;
678
679 tracing::info!(CVM_ALLOWED,
680 tee_type=?tee_call.map(|tee| tee.tee_type()),
681 secure_boot=attestation_vm_config.secure_boot,
682 tpm_enabled=attestation_vm_config.tpm_enabled,
683 tpm_persisted=attestation_vm_config.tpm_persisted,
684 hardware_sealing_supported=tee_call.and_then(|tee| tee.supports_get_derived_key()).is_some(),
687 hardware_sealing_policy=?attestation_vm_config.hardware_sealing_policy,
688 "Reading security profile");
689
690 let SecurityProfile { mut agent_data } = vmgs::read_security_profile(vmgs)
694 .await
695 .map_err(AttestationErrorInner::ReadSecurityProfile)?;
696
697 let require_hardware_sealing = tee_call.is_some()
706 && suppress_attestation
707 && matches!(
708 guest_state_encryption_policy,
709 GuestStateEncryptionPolicy::HardwareSealing
710 )
711 && !matches!(
712 attestation_vm_config.hardware_sealing_policy,
713 HardwareSealingPolicy::None
714 );
715
716 if matches!(tee_call.map(|tee| tee.tee_type()), Some(TeeType::Tdx))
723 && matches!(
724 attestation_vm_config.hardware_sealing_policy,
725 HardwareSealingPolicy::Signer
726 )
727 {
728 tracing::error!(
729 CVM_ALLOWED,
730 "signer-based hardware sealing is not supported on TDX; TDX has no \
731 identity key-policy register to bind a measurement-independent key to"
732 );
733 if require_hardware_sealing {
737 return Err(
738 AttestationErrorInner::HardwareSealingRequestedButNotAvailable {
739 tee_available: tee_call.is_some(),
740 hardware_sealing_policy: attestation_vm_config.hardware_sealing_policy,
741 }
742 .into(),
743 );
744 }
745 }
746
747 if !suppress_attestation
752 && matches!(
753 guest_state_encryption_policy,
754 GuestStateEncryptionPolicy::HardwareSealing
755 )
756 {
757 tracing::warn!(
758 CVM_ALLOWED,
759 ?guest_state_encryption_policy,
760 hardware_sealing_policy = ?attestation_vm_config.hardware_sealing_policy,
761 "host requested exclusive hardware sealing in stateful mode; \
762 ignoring and proceeding with the normal attestation flow"
763 );
764 }
765
766 if suppress_attestation && !require_hardware_sealing {
769 if matches!(
776 guest_state_encryption_policy,
777 GuestStateEncryptionPolicy::HardwareSealing
778 ) {
779 return Err(
780 AttestationErrorInner::HardwareSealingRequestedButNotAvailable {
781 tee_available: tee_call.is_some(),
782 hardware_sealing_policy: attestation_vm_config.hardware_sealing_policy,
783 }
784 .into(),
785 );
786 }
787
788 tracing::info!(
789 CVM_ALLOWED,
790 ?guest_state_encryption_policy,
791 hardware_sealing_policy = ?attestation_vm_config.hardware_sealing_policy,
792 tee_available = tee_call.is_some(),
793 "Suppressing attestation; VMGS encryption is bypassed"
794 );
795
796 return Ok(PlatformAttestationData {
797 host_attestation_settings: HostAttestationSettings {
798 refresh_tpm_seeds: false,
799 },
800 agent_data: Some(agent_data.to_vec()),
801 guest_secret_key: None,
802 runtime_tcb_floor: None,
803 });
804 }
805
806 let (mut key_protector_by_id, vm_id_changed) = if !require_hardware_sealing {
807 tracing::info!(CVM_ALLOWED, "Reading VM ID from VMGS");
809 let key_protector_by_id = match vmgs::read_key_protector_by_id(vmgs).await {
810 Ok(key_protector_by_id) => KeyProtectorById {
811 inner: key_protector_by_id,
812 found_id: true,
813 },
814 Err(vmgs::ReadFromVmgsError::EntryNotFound(_)) => KeyProtectorById {
815 inner: openhcl_attestation_protocol::vmgs::KeyProtectorById::new_zeroed(),
816 found_id: false,
817 },
818 Err(e) => { Err(AttestationErrorInner::ReadKeyProtectorById(e)) }?,
819 };
820
821 let vm_id_changed = if key_protector_by_id.found_id {
823 let changed = key_protector_by_id.inner.id_guid != bios_guid;
824 if changed {
825 tracing::info!("VM Id has changed since last boot");
826 };
827 changed
828 } else {
829 false
832 };
833
834 (key_protector_by_id, vm_id_changed)
835 } else {
836 (
838 KeyProtectorById {
839 inner: openhcl_attestation_protocol::vmgs::KeyProtectorById::new_zeroed(),
840 found_id: false,
841 },
842 false,
843 )
844 };
845
846 let vmgs_encrypted: bool = vmgs.encrypted();
850 let max_retry = if vmgs_encrypted {
851 MAXIMUM_RETRY_COUNT
852 } else {
853 NO_RETRY_COUNT
854 };
855
856 let mut timer = pal_async::timer::PolledTimer::new(&driver);
857 let mut i = 0;
858 let mut boot_tcb_floor = runtime_sealing::BootTcbFloor::new(tee_call, attestation_vm_config);
861
862 let UnlockResult {
863 state_refresh_request: state_refresh_request_from_gsp,
864 hardware_sealed,
865 } = loop {
866 tracing::info!(CVM_ALLOWED, attempt = i, "attempt to unlock VMGS file");
867
868 let response = try_unlock_vmgs(
869 get,
870 bios_guid,
871 attestation_vm_config,
872 vmgs,
873 tee_call,
874 guest_state_encryption_policy,
875 strict_encryption_policy,
876 require_hardware_sealing,
877 &mut agent_data,
878 &mut key_protector_by_id,
879 &mut boot_tcb_floor,
880 )
881 .await;
882
883 match response {
884 Ok(result) => break result,
885 Err((e, false)) => Err(e)?,
886 Err((e, true)) => {
887 if i >= max_retry - 1 {
888 Err(e)?
889 }
890 }
891 }
892
893 timer.sleep(std::time::Duration::new(1, 0)).await;
895 i += 1;
896 };
897
898 let host_attestation_settings = HostAttestationSettings {
899 refresh_tpm_seeds: { state_refresh_request_from_gsp | vm_id_changed },
900 };
901
902 tracing::info!(
903 CVM_ALLOWED,
904 state_refresh_request_from_gsp = state_refresh_request_from_gsp,
905 vm_id_changed = vm_id_changed,
906 "determine if refreshing tpm seeds is needed"
907 );
908
909 let guest_secret_key = match vmgs::read_guest_secret_key(vmgs).await {
911 Ok(data) => Some(data.guest_secret_key.to_vec()),
912 Err(vmgs::ReadFromVmgsError::EntryNotFound(_)) => None,
913 Err(e) => return Err(AttestationErrorInner::ReadGuestSecretKey(e).into()),
914 };
915
916 Ok(PlatformAttestationData {
917 host_attestation_settings,
918 agent_data: Some(agent_data.to_vec()),
919 guest_secret_key,
920 runtime_tcb_floor: boot_tcb_floor.finish().filter(|_| hardware_sealed),
921 })
922}
923
924async fn unlock_vmgs_data_store(
931 vmgs: &mut Vmgs,
932 vmgs_encrypted: bool,
933 key_protector: &mut KeyProtector,
934 key_protector_by_id: &mut KeyProtectorById,
935 hardware_key_protector: Option<HardwareKeyProtectorV3>,
936 derived_keys: Option<Keys>,
937 key_protector_settings: KeyProtectorSettings,
938 bios_guid: Guid,
939) -> Result<(), UnlockVmgsDataStoreError> {
940 let mut new_key = false; let Some(Keys {
943 ingress: new_ingress_key,
944 decrypt_egress: old_egress_key,
945 encrypt_egress: new_egress_key,
946 }) = derived_keys
947 else {
948 tracing::info!(
949 CVM_ALLOWED,
950 "Encryption disabled, skipping unlock vmgs data store"
951 );
952 return Ok(());
953 };
954
955 if !constant_time_eq::constant_time_eq_32(&new_ingress_key, &new_egress_key) {
956 tracing::trace!(CVM_ALLOWED, "EgressKey is different than IngressKey");
957 new_key = true;
958 }
959
960 let mut provision = false;
962 if vmgs_encrypted {
963 tracing::info!(CVM_ALLOWED, "Decrypting vmgs file...");
964 if let Err(e) = vmgs.unlock_with_encryption_key(&new_ingress_key).await {
965 if let Some(key) = old_egress_key {
966 tracing::info!(CVM_ALLOWED, "Old EgressKey found");
969 vmgs.unlock_with_encryption_key(&key)
970 .await
971 .map_err(UnlockVmgsDataStoreError::VmgsUnlockUsingExistingEgressKey)?;
972 } else {
973 Err(UnlockVmgsDataStoreError::VmgsUnlockUsingExistingIngressKey(
974 e,
975 ))?
976 }
977 }
978 } else {
979 tracing::info!(
981 CVM_ALLOWED,
982 "vmgs data store is not encrypted, provisioning."
983 );
984 provision = true;
985 }
986
987 tracing::info!(
988 CVM_ALLOWED,
989 should_write_kp = key_protector_settings.should_write_kp,
990 use_gsp_by_id = key_protector_settings.use_gsp_by_id,
991 use_hardware_unlock = key_protector_settings.use_hardware_unlock,
992 "key protector settings"
993 );
994
995 if key_protector_settings.should_write_kp {
996 vmgs::write_key_protector(key_protector, vmgs)
998 .await
999 .map_err(UnlockVmgsDataStoreError::WriteKeyProtector)?;
1000
1001 if key_protector_settings.use_gsp_by_id {
1002 vmgs::write_key_protector_by_id(&mut key_protector_by_id.inner, vmgs, false, bios_guid)
1003 .await
1004 .map_err(UnlockVmgsDataStoreError::WriteKeyProtectorById)?;
1005 }
1006 }
1007
1008 if provision || new_key {
1009 vmgs.update_encryption_key(&new_egress_key, EncryptionAlgorithm::AES_GCM)
1013 .await
1014 .map_err(UnlockVmgsDataStoreError::UpdateVmgsEncryptionKey)?;
1015 }
1016
1017 persist_all_key_protectors(
1019 vmgs,
1020 key_protector,
1021 key_protector_by_id,
1022 hardware_key_protector.as_ref(),
1023 bios_guid,
1024 key_protector_settings,
1025 )
1026 .await
1027 .map_err(UnlockVmgsDataStoreError::PersistAllKeyProtectors)
1028}
1029
1030#[expect(clippy::fn_params_excessive_bools)]
1047async fn get_derived_keys(
1048 get: &GuestEmulationTransportClient,
1049 tee_call: Option<&dyn TeeCall>,
1050 vmgs: &mut Vmgs,
1051 key_protector: &mut KeyProtector,
1052 key_protector_by_id: &mut KeyProtectorById,
1053 bios_guid: Guid,
1054 attestation_vm_config: &AttestationVmConfig,
1055 is_encrypted: bool,
1056 ingress_rsa_kek: Option<&RsaKeyPair>,
1057 wrapped_des_key: Option<&[u8]>,
1058 key_derivation_policy: Option<KeyDerivationPolicy>,
1059 guest_state_encryption_policy: GuestStateEncryptionPolicy,
1060 strict_encryption_policy: bool,
1061 require_hardware_sealing: bool,
1062 skip_hw_unsealing: bool,
1063) -> Result<DerivedKeyResult, GetDerivedKeysError> {
1064 tracing::info!(
1065 CVM_ALLOWED,
1066 ?guest_state_encryption_policy,
1067 strict_encryption_policy,
1068 "encryption policy"
1069 );
1070
1071 let mut key_protector_settings = KeyProtectorSettings {
1072 should_write_kp: true,
1073 use_gsp_by_id: false,
1074 use_hardware_unlock: false,
1075 decrypt_gsp_type: GspType::None,
1076 encrypt_gsp_type: GspType::None,
1077 };
1078
1079 let mut derived_keys = Keys {
1080 ingress: [0u8; AES_GCM_KEY_LENGTH],
1081 decrypt_egress: None,
1082 encrypt_egress: [0u8; AES_GCM_KEY_LENGTH],
1083 };
1084
1085 let ingress_idx = (key_protector.active_kp % 2) as usize;
1087 let egress_idx = if ingress_idx == 0 { 1 } else { 0 } as usize;
1088
1089 let found_dek = !key_protector.dek[ingress_idx]
1090 .dek_buffer
1091 .iter()
1092 .all(|&x| x == 0);
1093
1094 let (ingress_key, mut decrypt_egress_key, encrypt_egress_key, no_kek) =
1096 if let Some(ingress_kek) = ingress_rsa_kek {
1097 let keys = match key_protector.unwrap_and_rotate_keys(
1098 ingress_kek,
1099 wrapped_des_key,
1100 ingress_idx,
1101 egress_idx,
1102 ) {
1103 Ok(keys) => keys,
1104 Err(e)
1105 if matches!(
1106 e,
1107 GetKeysFromKeyProtectorError::DesKeyRsaUnwrap(_)
1108 | GetKeysFromKeyProtectorError::IngressDekRsaUnwrap(_)
1109 ) =>
1110 {
1111 get.event_log_fatal(
1112 guest_emulation_transport::api::EventLogId::DEK_DECRYPTION_FAILED,
1113 )
1114 .await;
1115
1116 return Err(GetDerivedKeysError::GetKeysFromKeyProtector(e));
1117 }
1118 Err(e) => return Err(GetDerivedKeysError::GetKeysFromKeyProtector(e)),
1119 };
1120 (
1121 keys.ingress,
1122 keys.decrypt_egress,
1123 keys.encrypt_egress,
1124 false,
1125 )
1126 } else {
1127 (
1128 [0u8; AES_GCM_KEY_LENGTH],
1129 None,
1130 [0u8; AES_GCM_KEY_LENGTH],
1131 true,
1132 )
1133 };
1134
1135 let existing_unencrypted = !vmgs.encrypted() && !vmgs.was_provisioned_this_boot();
1137 let is_gsp_by_id = key_protector_by_id.found_id && key_protector_by_id.inner.ported != 1;
1138 let is_gsp = key_protector.gsp[ingress_idx].gsp_length != 0;
1139 tracing::info!(
1140 CVM_ALLOWED,
1141 is_encrypted,
1142 is_gsp_by_id,
1143 is_gsp,
1144 found_dek,
1145 "initial vmgs encryption state"
1146 );
1147 let mut requires_gsp_by_id = is_gsp_by_id;
1148
1149 let (gsp_response, gsp_available, no_gsp, requires_gsp) = if require_hardware_sealing {
1151 tracing::info!(
1156 CVM_ALLOWED,
1157 "Hardware sealing is required, skip GSP callout"
1158 );
1159 (GuestStateProtection::new_zeroed(), false, true, false)
1160 } else {
1161 tracing::info!(CVM_ALLOWED, "attempting GSP");
1162
1163 let response = get_gsp_data(get, key_protector).await;
1164
1165 tracing::info!(
1166 CVM_ALLOWED,
1167 request_data_length_in_vmgs = key_protector.gsp[ingress_idx].gsp_length,
1168 no_rpc_server = response.extended_status_flags.no_rpc_server(),
1169 requires_rpc_server = response.extended_status_flags.requires_rpc_server(),
1170 encrypted_gsp_length = response.encrypted_gsp.length,
1171 "GSP response"
1172 );
1173
1174 let no_gsp_available =
1175 response.extended_status_flags.no_rpc_server() || response.encrypted_gsp.length == 0;
1176
1177 let no_gsp = no_gsp_available
1178 || (matches!(
1182 guest_state_encryption_policy,
1183 GuestStateEncryptionPolicy::Auto
1184 ) && (is_gsp_by_id || existing_unencrypted))
1185 || (matches!(
1187 guest_state_encryption_policy,
1188 GuestStateEncryptionPolicy::GspById | GuestStateEncryptionPolicy::None
1189 ) && (!is_gsp || strict_encryption_policy));
1190
1191 let requires_gsp = is_gsp
1192 || response.extended_status_flags.requires_rpc_server()
1193 || (matches!(
1194 guest_state_encryption_policy,
1195 GuestStateEncryptionPolicy::GspKey
1196 ) && strict_encryption_policy);
1197
1198 if is_encrypted && !requires_gsp_by_id && !requires_gsp && !found_dek {
1201 requires_gsp_by_id = true;
1202 }
1203
1204 (response, !no_gsp_available, no_gsp, requires_gsp)
1205 };
1206
1207 let (gsp_response_by_id, gsp_by_id_available, no_gsp_by_id) = if !require_hardware_sealing
1211 && (no_gsp || requires_gsp_by_id)
1212 {
1213 tracing::info!(CVM_ALLOWED, "attempting GSP By Id");
1214
1215 let gsp_response_by_id = get
1216 .guest_state_protection_data_by_id()
1217 .await
1218 .map_err(GetDerivedKeysError::FetchGuestStateProtectionById)?;
1219
1220 let no_gsp_by_id_available = gsp_response_by_id.extended_status_flags.no_registry_file();
1221
1222 let no_gsp_by_id = no_gsp_by_id_available
1223 || (matches!(
1226 guest_state_encryption_policy,
1227 GuestStateEncryptionPolicy::Auto
1228 ) && existing_unencrypted)
1229 || (matches!(
1231 guest_state_encryption_policy,
1232 GuestStateEncryptionPolicy::None
1233 ) && (!requires_gsp_by_id || strict_encryption_policy));
1234
1235 if no_gsp_by_id && requires_gsp_by_id {
1236 Err(GetDerivedKeysError::GspByIdRequiredButNotFound)?
1237 }
1238
1239 (
1240 gsp_response_by_id,
1241 Some(!no_gsp_by_id_available),
1242 no_gsp_by_id,
1243 )
1244 } else {
1245 (GuestStateProtectionById::new_zeroed(), None, true)
1246 };
1247
1248 if (no_kek && found_dek)
1250 || (no_gsp && requires_gsp)
1251 || (no_gsp_by_id && requires_gsp_by_id)
1252 || (require_hardware_sealing && is_encrypted)
1253 {
1254 let (hardware_key_protector, hardware_derived_keys) = if let Some(tee_call) = tee_call {
1256 let hardware_key_protector = match vmgs::read_hardware_key_protector(vmgs).await {
1257 Ok(hardware_key_protector) => Some(hardware_key_protector),
1258 Err(e) => {
1259 tracing::warn!(
1261 CVM_ALLOWED,
1262 error = &e as &dyn std::error::Error,
1263 "failed to read HW_KEY_PROTECTOR from Vmgs"
1264 );
1265 None
1266 }
1267 };
1268
1269 let hardware_derived_keys = tee_call.supports_get_derived_key().and_then(|tee_call| {
1270 if let Some(hardware_key_protector) = &hardware_key_protector {
1271 let Some(policy) = hardware_key_protector.key_derivation_policy() else {
1275 tracing::error!(
1276 CVM_ALLOWED,
1277 version = hardware_key_protector.version(),
1278 current_version = HW_KEY_PROTECTOR_CURRENT_VERSION,
1279 "incompatible HW_KEY_PROTECTOR; skip VMGS DEK unsealing with hardware key protector."
1280 );
1281 return None;
1282 };
1283
1284 match HardwareDerivedKeys::derive_key(tee_call, attestation_vm_config, policy) {
1285 Ok(hardware_derived_key) => Some(hardware_derived_key),
1286 Err(e) => {
1287 tracing::warn!(
1289 CVM_ALLOWED,
1290 error = &e as &dyn std::error::Error,
1291 version = hardware_key_protector.version(),
1292 "failed to derive hardware keys using HW_KEY_PROTECTOR",
1293 );
1294 None
1295 }
1296 }
1297 } else {
1298 None
1299 }
1300 });
1301
1302 if skip_hw_unsealing {
1308 if hardware_key_protector.is_some() && hardware_derived_keys.is_some() {
1309 tracing::warn!(
1310 CVM_ALLOWED,
1311 "Skipping hardware unsealing of VMGS DEK as signaled by IGVM agent"
1312 );
1313 get.event_log_fatal(
1314 guest_emulation_transport::api::EventLogId::DEK_HARDWARE_UNSEALING_SKIPPED,
1315 )
1316 .await;
1317
1318 (None, None)
1319 } else {
1320 tracing::info!(
1321 CVM_ALLOWED,
1322 hardware_key_protector = hardware_key_protector.is_some(),
1323 hardware_derived_keys = hardware_derived_keys.is_some(),
1324 "skip_hw_unsealing signaled but hardware key data not available, \
1325 falling through to scheme-specific error"
1326 );
1327 (None, None)
1328 }
1329 } else {
1330 (hardware_key_protector, hardware_derived_keys)
1331 }
1332 } else {
1333 (None, None)
1334 };
1335
1336 if let (Some(hardware_key_protector), Some(hardware_derived_keys)) =
1337 (hardware_key_protector, hardware_derived_keys)
1338 {
1339 let dek = match hardware_key_protector.unseal_key(&hardware_derived_keys) {
1340 Ok(dek) => dek,
1341 Err(e @ HardwareKeySealingError::HardwareKeyProtectorHmacVerificationFailed)
1342 if require_hardware_sealing =>
1343 {
1344 tracing::error!(
1345 CVM_ALLOWED,
1346 "hardware unsealing failed due to inconsistent hardware-derived keys"
1347 );
1348
1349 get.event_log_fatal(
1350 guest_emulation_transport::api::EventLogId::DEK_HARDWARE_SEALING_INVALID_KEY,
1351 )
1352 .await;
1353
1354 return Err(GetDerivedKeysError::UnsealIngressKeyUsingHardwareDerivedKeys(e));
1355 }
1356 Err(e) => {
1357 return Err(GetDerivedKeysError::UnsealIngressKeyUsingHardwareDerivedKeys(e));
1358 }
1359 };
1360
1361 derived_keys.ingress = dek;
1362 derived_keys.decrypt_egress = None;
1363
1364 let hardware_key_protector = if require_hardware_sealing && is_encrypted {
1365 let mut new_dek = [0u8; AES_GCM_KEY_LENGTH];
1367 getrandom::fill(&mut new_dek).expect("rng failure");
1368
1369 let updated_hardware_key_protector =
1370 hardware_key_sealing::seal_key(&hardware_derived_keys, &new_dek)
1371 .map_err(GetDerivedKeysError::SealEgressKeyUsingHardwareDerivedKeys)?;
1372
1373 derived_keys.encrypt_egress = new_dek;
1374
1375 tracing::info!(
1376 CVM_ALLOWED,
1377 "Non-first boot with VMGS hardware sealing mode. Generate a new random key for VMGS DEK rotation."
1378 );
1379
1380 updated_hardware_key_protector
1383 } else {
1384 derived_keys.encrypt_egress = derived_keys.ingress;
1385
1386 tracing::warn!(
1387 CVM_ALLOWED,
1388 "Using hardware-derived key to recover VMGS DEK"
1389 );
1390
1391 hardware_key_sealing::seal_key(&hardware_derived_keys, &derived_keys.ingress)
1394 .map_err(GetDerivedKeysError::SealEgressKeyUsingHardwareDerivedKeys)?
1395 };
1396
1397 key_protector_settings.should_write_kp = false;
1398 key_protector_settings.use_hardware_unlock = true;
1399
1400 return Ok(DerivedKeyResult {
1401 derived_keys: Some(derived_keys),
1402 key_protector_settings,
1403 gsp_extended_status_flags: gsp_response.extended_status_flags,
1404 hardware_key_protector: Some(hardware_key_protector),
1405 hardware_key_protector_written: false,
1406 });
1407 } else {
1408 if require_hardware_sealing && is_encrypted {
1409 get.event_log_fatal(
1410 guest_emulation_transport::api::EventLogId::DEK_HARDWARE_SEALING_FAILED,
1411 )
1412 .await;
1413 return Err(GetDerivedKeysError::GetIngressKeyFromHardwareKeyProtectorFailed);
1414 } else if no_kek && found_dek {
1415 return Err(GetDerivedKeysError::GetIngressKeyFromKpFailed);
1416 } else if no_gsp && requires_gsp {
1417 return Err(GetDerivedKeysError::GetIngressKeyFromKGspFailed);
1418 } else {
1419 return Err(GetDerivedKeysError::GetIngressKeyFromKGspByIdFailed);
1421 }
1422 }
1423 }
1424
1425 tracing::info!(
1426 CVM_ALLOWED,
1427 kek = !no_kek,
1428 gsp_available,
1429 gsp = !no_gsp,
1430 gsp_by_id_available = ?gsp_by_id_available,
1431 gsp_by_id = !no_gsp_by_id,
1432 hw_sealing = require_hardware_sealing,
1433 "Encryption sources"
1434 );
1435
1436 let hardware_derived_keys = tee_call
1438 .and_then(|tee_call| tee_call.supports_get_derived_key())
1439 .and_then(|tee_call| {
1440 if let Some(policy) = key_derivation_policy {
1441 match HardwareDerivedKeys::derive_key(tee_call, attestation_vm_config, policy) {
1442 Ok(keys) => Some(keys),
1443 Err(e) => {
1444 tracing::warn!(
1446 CVM_ALLOWED,
1447 error = &e as &dyn std::error::Error,
1448 "failed to derive hardware keys"
1449 );
1450 None
1451 }
1452 }
1453 } else {
1454 None
1455 }
1456 });
1457
1458 if require_hardware_sealing && !is_encrypted {
1460 let Some(hardware_derived_keys) = hardware_derived_keys else {
1461 get.event_log_fatal(
1462 guest_emulation_transport::api::EventLogId::DEK_HARDWARE_SEALING_FAILED,
1463 )
1464 .await;
1465 return Err(GetDerivedKeysError::HardwareSealingRequiredButNotSupported);
1466 };
1467
1468 let mut new_dek = [0u8; AES_GCM_KEY_LENGTH];
1469 getrandom::fill(&mut new_dek).expect("rng failure");
1470
1471 let hardware_key_protector =
1472 match hardware_key_sealing::seal_key(&hardware_derived_keys, &new_dek) {
1473 Ok(hardware_key_protector) => hardware_key_protector,
1474 Err(e) => {
1475 get.event_log_fatal(
1476 guest_emulation_transport::api::EventLogId::DEK_HARDWARE_SEALING_FAILED,
1477 )
1478 .await;
1479 return Err(GetDerivedKeysError::SealEgressKeyUsingHardwareDerivedKeys(
1480 e,
1481 ));
1482 }
1483 };
1484
1485 derived_keys.ingress = [0u8; AES_GCM_KEY_LENGTH];
1486 derived_keys.decrypt_egress = None;
1487 derived_keys.encrypt_egress = new_dek;
1488
1489 tracing::info!(
1490 CVM_ALLOWED,
1491 "First boot with VMGS hardware sealing mode. Generate a new random key for VMGS encryption."
1492 );
1493
1494 return Ok(DerivedKeyResult {
1495 derived_keys: Some(derived_keys),
1496 key_protector_settings,
1497 gsp_extended_status_flags: gsp_response.extended_status_flags,
1498 hardware_key_protector: Some(hardware_key_protector),
1499 hardware_key_protector_written: false,
1500 });
1501 }
1502
1503 if no_kek && no_gsp && no_gsp_by_id {
1505 if is_encrypted {
1506 Err(GetDerivedKeysError::DisableVmgsEncryptionFailed)?
1507 }
1508 match guest_state_encryption_policy {
1509 GuestStateEncryptionPolicy::GspById
1511 | GuestStateEncryptionPolicy::GspKey
1512 | GuestStateEncryptionPolicy::HardwareSealing => {
1513 Err(GetDerivedKeysError::EncryptionRequiredButNotFound)?
1514 }
1515 GuestStateEncryptionPolicy::Auto | GuestStateEncryptionPolicy::None => {
1516 tracing::info!(CVM_ALLOWED, "No VMGS encryption used.");
1517
1518 return Ok(DerivedKeyResult {
1519 derived_keys: None,
1520 key_protector_settings,
1521 gsp_extended_status_flags: gsp_response.extended_status_flags,
1522 hardware_key_protector: None,
1523 hardware_key_protector_written: false,
1524 });
1525 }
1526 }
1527 }
1528
1529 let mut hardware_key_protector_written = false;
1530
1531 if no_gsp && no_gsp_by_id {
1533 tracing::info!(CVM_ALLOWED, "No GSP used with SKR");
1534
1535 derived_keys.ingress = ingress_key;
1536 derived_keys.decrypt_egress = decrypt_egress_key;
1537 derived_keys.encrypt_egress = encrypt_egress_key;
1538
1539 if let Some(hardware_derived_keys) = hardware_derived_keys {
1540 let hardware_key_protector = hardware_key_sealing::seal_key(
1541 &hardware_derived_keys,
1542 &derived_keys.encrypt_egress,
1543 )
1544 .map_err(GetDerivedKeysError::SealEgressKeyUsingHardwareDerivedKeys)?;
1545 vmgs::write_hardware_key_protector(&hardware_key_protector, vmgs)
1546 .await
1547 .map_err(GetDerivedKeysError::VmgsWriteHardwareKeyProtector)?;
1548 hardware_key_protector_written = true;
1549
1550 tracing::info!(CVM_ALLOWED, "hardware key protector updated (no GSP used)");
1551 }
1552
1553 return Ok(DerivedKeyResult {
1554 derived_keys: Some(derived_keys),
1555 key_protector_settings,
1556 gsp_extended_status_flags: gsp_response.extended_status_flags,
1557 hardware_key_protector: None,
1558 hardware_key_protector_written,
1559 });
1560 }
1561
1562 if (no_kek && no_gsp) || requires_gsp_by_id {
1565 let derived_keys_by_id =
1566 get_derived_keys_by_id(key_protector_by_id, bios_guid, gsp_response_by_id)
1567 .map_err(GetDerivedKeysError::GetDerivedKeyById)?;
1568
1569 if no_kek && no_gsp {
1570 if matches!(
1571 guest_state_encryption_policy,
1572 GuestStateEncryptionPolicy::GspById | GuestStateEncryptionPolicy::Auto
1573 ) {
1574 tracing::info!(CVM_ALLOWED, "Using GspById");
1575 } else {
1576 tracing::warn!(CVM_ALLOWED, "Allowing GspById");
1586 };
1587
1588 key_protector_settings.should_write_kp = false;
1590 key_protector_settings.use_gsp_by_id = true;
1591 key_protector_settings.decrypt_gsp_type = GspType::GspById;
1592 key_protector_settings.encrypt_gsp_type = GspType::GspById;
1593
1594 return Ok(DerivedKeyResult {
1595 derived_keys: Some(derived_keys_by_id),
1596 key_protector_settings,
1597 gsp_extended_status_flags: gsp_response.extended_status_flags,
1598 hardware_key_protector: None,
1599 hardware_key_protector_written: false,
1600 });
1601 }
1602
1603 derived_keys.ingress = derived_keys_by_id.ingress;
1604
1605 tracing::info!(
1606 CVM_ALLOWED,
1607 op_type = ?LogOpType::ConvertEncryptionType,
1608 "Converting GSP method."
1609 );
1610 }
1611
1612 let egress_seed;
1613 let mut ingress_seed = None;
1614
1615 if requires_gsp_by_id || no_gsp {
1621 if found_dek {
1624 if requires_gsp_by_id {
1625 ingress_seed = Some(
1626 gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize]
1627 .to_vec(),
1628 );
1629 key_protector_settings.decrypt_gsp_type = GspType::GspById;
1630 } else {
1631 derived_keys.ingress = ingress_key;
1632 }
1633 } else {
1634 key_protector_settings.decrypt_gsp_type = GspType::GspById;
1635 }
1636
1637 if no_gsp {
1639 egress_seed =
1640 gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize].to_vec();
1641 key_protector_settings.use_gsp_by_id = true;
1642 key_protector_settings.encrypt_gsp_type = GspType::GspById;
1643 } else {
1644 egress_seed =
1645 gsp_response.new_gsp.buffer[..gsp_response.new_gsp.length as usize].to_vec();
1646 key_protector_settings.encrypt_gsp_type = GspType::GspKey;
1647 }
1648 } else {
1649 if gsp_response.decrypted_gsp[ingress_idx].length == 0
1652 && gsp_response.decrypted_gsp[egress_idx].length == 0
1653 {
1654 tracing::info!(CVM_ALLOWED, "Applying GSP.");
1655
1656 egress_seed =
1659 gsp_response.new_gsp.buffer[..gsp_response.new_gsp.length as usize].to_vec();
1660
1661 if !no_kek {
1664 derived_keys.ingress = ingress_key;
1665 }
1666
1667 key_protector_settings.encrypt_gsp_type = GspType::GspKey;
1668 } else {
1669 tracing::info!(CVM_ALLOWED, "Using existing GSP.");
1670
1671 ingress_seed = Some(
1672 gsp_response.decrypted_gsp[ingress_idx].buffer
1673 [..gsp_response.decrypted_gsp[ingress_idx].length as usize]
1674 .to_vec(),
1675 );
1676
1677 if gsp_response.decrypted_gsp[egress_idx].length == 0 {
1678 egress_seed =
1680 gsp_response.new_gsp.buffer[..gsp_response.new_gsp.length as usize].to_vec();
1681 } else {
1682 egress_seed = gsp_response.decrypted_gsp[egress_idx].buffer
1687 [..gsp_response.decrypted_gsp[egress_idx].length as usize]
1688 .to_vec();
1689 key_protector_settings.should_write_kp = false;
1690 decrypt_egress_key = Some(encrypt_egress_key);
1691 }
1692
1693 key_protector_settings.decrypt_gsp_type = GspType::GspKey;
1694 key_protector_settings.encrypt_gsp_type = GspType::GspKey;
1695 }
1696 }
1697
1698 if let Some(seed) = ingress_seed {
1700 derived_keys.ingress = derive_key(&ingress_key, &seed, VMGS_KEY_DERIVE_LABEL)
1701 .map_err(GetDerivedKeysError::DeriveIngressKey)?;
1702 }
1703
1704 derived_keys.decrypt_egress = decrypt_egress_key
1706 .map(|key| derive_key(&key, &egress_seed, VMGS_KEY_DERIVE_LABEL))
1707 .transpose()
1708 .map_err(GetDerivedKeysError::DeriveEgressKey)?;
1709
1710 derived_keys.encrypt_egress =
1711 derive_key(&encrypt_egress_key, &egress_seed, VMGS_KEY_DERIVE_LABEL)
1712 .map_err(GetDerivedKeysError::DeriveEgressKey)?;
1713
1714 if key_protector_settings.should_write_kp {
1715 key_protector.gsp[egress_idx]
1717 .gsp_buffer
1718 .copy_from_slice(&gsp_response.encrypted_gsp.buffer);
1719 key_protector.gsp[egress_idx].gsp_length = gsp_response.encrypted_gsp.length;
1720
1721 if let Some(hardware_derived_keys) = hardware_derived_keys {
1722 let hardware_key_protector = hardware_key_sealing::seal_key(
1723 &hardware_derived_keys,
1724 &derived_keys.encrypt_egress,
1725 )
1726 .map_err(GetDerivedKeysError::SealEgressKeyUsingHardwareDerivedKeys)?;
1727
1728 vmgs::write_hardware_key_protector(&hardware_key_protector, vmgs)
1729 .await
1730 .map_err(GetDerivedKeysError::VmgsWriteHardwareKeyProtector)?;
1731 hardware_key_protector_written = true;
1732
1733 tracing::info!(CVM_ALLOWED, "hardware key protector updated");
1734 }
1735 }
1736
1737 if matches!(
1738 guest_state_encryption_policy,
1739 GuestStateEncryptionPolicy::GspKey | GuestStateEncryptionPolicy::Auto
1740 ) {
1741 tracing::info!(CVM_ALLOWED, "Using Gsp");
1742 } else {
1743 tracing::warn!(CVM_ALLOWED, "Allowing Gsp");
1750 }
1751
1752 Ok(DerivedKeyResult {
1753 derived_keys: Some(derived_keys),
1754 key_protector_settings,
1755 gsp_extended_status_flags: gsp_response.extended_status_flags,
1756 hardware_key_protector: None,
1757 hardware_key_protector_written,
1758 })
1759}
1760
1761fn get_derived_keys_by_id(
1763 key_protector_by_id: &mut KeyProtectorById,
1764 bios_guid: Guid,
1765 gsp_response_by_id: GuestStateProtectionById,
1766) -> Result<Keys, GetDerivedKeysByIdError> {
1767 let new_egress_key = derive_key(
1774 &gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize],
1775 bios_guid.as_bytes(),
1776 VMGS_KEY_DERIVE_LABEL,
1777 )
1778 .map_err(GetDerivedKeysByIdError::DeriveEgressKeyUsingCurrentVmId)?;
1779
1780 if new_egress_key.len() != AES_GCM_KEY_LENGTH {
1781 Err(GetDerivedKeysByIdError::InvalidDerivedEgressKeySize {
1782 key_size: new_egress_key.len(),
1783 expected_size: AES_GCM_KEY_LENGTH,
1784 })?
1785 }
1786
1787 let new_ingress_key = if key_protector_by_id.inner.id_guid != Guid::default() {
1790 derive_key(
1792 &gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize],
1793 key_protector_by_id.inner.id_guid.as_bytes(),
1794 VMGS_KEY_DERIVE_LABEL,
1795 )
1796 .map_err(GetDerivedKeysByIdError::DeriveIngressKeyUsingKeyProtectorId)?
1797 } else {
1798 new_egress_key
1800 };
1801
1802 if new_ingress_key.len() != AES_GCM_KEY_LENGTH {
1803 Err(GetDerivedKeysByIdError::InvalidDerivedIngressKeySize {
1804 key_size: new_ingress_key.len(),
1805 expected_size: AES_GCM_KEY_LENGTH,
1806 })?
1807 }
1808
1809 Ok(Keys {
1810 ingress: new_ingress_key,
1811 decrypt_egress: None,
1812 encrypt_egress: new_egress_key,
1813 })
1814}
1815
1816async fn get_gsp_data(
1818 get: &GuestEmulationTransportClient,
1819 key_protector: &mut KeyProtector,
1820) -> GuestStateProtection {
1821 use openhcl_attestation_protocol::vmgs::GSP_BUFFER_SIZE;
1822 use openhcl_attestation_protocol::vmgs::NUMBER_KP;
1823
1824 const_assert_eq!(guest_emulation_transport::api::NUMBER_GSP, NUMBER_KP as u32);
1825 const_assert_eq!(
1826 guest_emulation_transport::api::GSP_CIPHERTEXT_MAX,
1827 GSP_BUFFER_SIZE as u32
1828 );
1829
1830 let mut encrypted_gsp =
1831 [guest_emulation_transport::api::GspCiphertextContent::new_zeroed(); NUMBER_KP];
1832
1833 for (i, gsp) in encrypted_gsp.iter_mut().enumerate().take(NUMBER_KP) {
1834 if key_protector.gsp[i].gsp_length == 0 {
1835 continue;
1836 }
1837
1838 gsp.buffer[..key_protector.gsp[i].gsp_length as usize].copy_from_slice(
1839 &key_protector.gsp[i].gsp_buffer[..key_protector.gsp[i].gsp_length as usize],
1840 );
1841
1842 gsp.length = key_protector.gsp[i].gsp_length;
1843 }
1844
1845 get.guest_state_protection_data(encrypted_gsp, GspExtendedStatusFlags::new())
1846 .await
1847}
1848
1849async fn persist_all_key_protectors(
1851 vmgs: &mut Vmgs,
1852 key_protector: &mut KeyProtector,
1853 key_protector_by_id: &mut KeyProtectorById,
1854 hardware_key_protector: Option<&HardwareKeyProtectorV3>,
1855 bios_guid: Guid,
1856 key_protector_settings: KeyProtectorSettings,
1857) -> Result<(), PersistAllKeyProtectorsError> {
1858 use openhcl_attestation_protocol::vmgs::NUMBER_KP;
1859
1860 if key_protector_settings.use_gsp_by_id && !key_protector_settings.should_write_kp {
1861 vmgs::write_key_protector_by_id(&mut key_protector_by_id.inner, vmgs, false, bios_guid)
1862 .await
1863 .map_err(PersistAllKeyProtectorsError::KeyProtectorById)?;
1864 } else {
1865 if let Some(hardware_key_protector) = hardware_key_protector {
1871 vmgs::write_hardware_key_protector(hardware_key_protector, vmgs)
1872 .await
1873 .map_err(PersistAllKeyProtectorsError::HardwareKeyProtector)?;
1874 } else {
1875 key_protector.dek[key_protector.active_kp as usize % NUMBER_KP]
1877 .dek_buffer
1878 .fill(0);
1879 key_protector.gsp[key_protector.active_kp as usize % NUMBER_KP].gsp_length = 0;
1880 key_protector.active_kp += 1;
1881
1882 vmgs::write_key_protector(key_protector, vmgs)
1883 .await
1884 .map_err(PersistAllKeyProtectorsError::KeyProtector)?;
1885 }
1886
1887 if !key_protector_settings.use_gsp_by_id
1889 && key_protector_by_id.found_id
1890 && key_protector_by_id.inner.ported == 0
1891 {
1892 key_protector_by_id.inner.ported = 1;
1893 vmgs::write_key_protector_by_id(&mut key_protector_by_id.inner, vmgs, true, bios_guid)
1894 .await
1895 .map_err(PersistAllKeyProtectorsError::KeyProtectorById)?;
1896 }
1897 }
1898
1899 Ok(())
1900}
1901
1902#[derive(Debug, Serialize, Deserialize)]
1903struct ProvenanceJwtBody {
1904 #[serde(rename = "VMGSID")]
1905 pub vmgsid: String,
1906}
1907
1908pub fn get_provenance_claims(prov_file: &[u8]) -> Result<VmgsProvisioner, Error> {
1910 let jwt = JwtHelper::<ProvenanceJwtBody>::from(prov_file)
1911 .map_err(ProvenanceError::DecodeProvenanceDoc)
1912 .map_err(AttestationErrorInner::Provenance)?;
1913 let valid = jwt
1914 .verify_signature()
1915 .map_err(ProvenanceError::VerifySignature)
1916 .map_err(AttestationErrorInner::Provenance)?;
1917
1918 if !valid {
1919 return Err(Error(AttestationErrorInner::Provenance(
1920 ProvenanceError::InvalidSignature,
1921 )));
1922 }
1923
1924 let cert_chain = jwt
1925 .cert_chain()
1926 .map_err(ProvenanceError::DecodeProvenanceDoc)
1927 .map_err(AttestationErrorInner::Provenance)?;
1928 let leaf = &cert_chain[0];
1929
1930 let sn = leaf
1931 .subject_common_name()
1932 .map_err(ProvenanceError::X509Error)
1933 .map_err(AttestationErrorInner::Provenance)?
1934 .ok_or(AttestationErrorInner::Provenance(
1935 ProvenanceError::MissingLeafCertSubjectName,
1936 ))?;
1937
1938 let root = cert_chain.last().ok_or(AttestationErrorInner::Provenance(
1939 ProvenanceError::InvalidRootCert,
1940 ))?;
1941 let digest = sha_256(
1942 &(root
1943 .to_der()
1944 .map_err(ProvenanceError::X509Error)
1945 .map_err(AttestationErrorInner::Provenance)?),
1946 );
1947 let signer = format!(
1948 "did:x509:0:sha256:{}:subject:{}",
1949 hex::encode_upper(digest),
1950 sn
1951 );
1952 let vmgsid = jwt.jwt.body.vmgsid;
1953
1954 Ok(VmgsProvisioner {
1955 id: Guid::parse(vmgsid.as_bytes())
1956 .map_err(ProvenanceError::ParseVmgsid)
1957 .map_err(AttestationErrorInner::Provenance)?,
1958 signer,
1959 })
1960}
1961
1962pub fn derive_vmgsid(seed_file: &[u8]) -> Result<Guid, Error> {
1964 let seed_file_str = str::from_utf8(seed_file)
1965 .map_err(ProvenanceError::InvalidVmgsidData)
1966 .map_err(AttestationErrorInner::Provenance)?;
1967
1968 let parts = seed_file_str
1973 .split(',')
1974 .map(|s| s.trim())
1975 .collect::<Vec<&str>>();
1976 if parts.len() < 3 {
1977 Err(AttestationErrorInner::Provenance(
1978 ProvenanceError::ParseVmgsidSeedData,
1979 ))?;
1980 }
1981
1982 let seed = hex::decode(parts[0])
1983 .map_err(ProvenanceError::DecodeVmgsidData)
1984 .map_err(AttestationErrorInner::Provenance)?;
1985 let label = hex::decode(parts[1])
1986 .map_err(ProvenanceError::DecodeVmgsidData)
1987 .map_err(AttestationErrorInner::Provenance)?;
1988 let context = hex::decode(parts[2])
1989 .map_err(ProvenanceError::DecodeVmgsidData)
1990 .map_err(AttestationErrorInner::Provenance)?;
1991
1992 let key = crypto::kbkdf::kbkdf_hmac(&seed, &context, &label, 32, crypto::HashAlgorithm::Sha256)
1993 .map_err(ProvenanceError::KdfError)
1994 .map_err(AttestationErrorInner::Provenance)?;
1995
1996 Ok(Guid::from_slice(&key[0..16].try_into().unwrap()))
1997}
1998
1999#[cfg(test)]
2001pub mod test_utils {
2002 use tee_call::GetAttestationReportResult;
2003 use tee_call::HW_DERIVED_KEY_LENGTH;
2004 use tee_call::KeyDerivationPolicy;
2005 use tee_call::REPORT_DATA_SIZE;
2006 use tee_call::TeeCall;
2007 use tee_call::TeeCallGetDerivedKey;
2008 use tee_call::TeeType;
2009
2010 pub struct MockTeeCall {
2012 pub measurement: [u8; 32],
2014 pub tcb_version: u64,
2016 }
2017
2018 impl MockTeeCall {
2019 pub fn new(measurement: [u8; 32]) -> Self {
2021 Self {
2022 measurement,
2023 tcb_version: 0x1234,
2024 }
2025 }
2026
2027 pub fn update_measurement(&mut self, measurement: [u8; 32]) {
2029 self.measurement = measurement;
2030 }
2031 }
2032
2033 impl TeeCall for MockTeeCall {
2034 fn get_attestation_report(
2035 &self,
2036 report_data: &[u8; REPORT_DATA_SIZE],
2037 ) -> Result<GetAttestationReportResult, tee_call::Error> {
2038 let mut report =
2039 [0x6c; openhcl_attestation_protocol::igvm_attest::get::SNP_VM_REPORT_SIZE];
2040 report[..REPORT_DATA_SIZE].copy_from_slice(report_data);
2041
2042 Ok(GetAttestationReportResult {
2043 report: report.to_vec(),
2044 key_derivation_svn: Some(tee_call::KeyDerivationSvn::Snp {
2045 tcb_version: self.tcb_version,
2046 }),
2047 })
2048 }
2049
2050 fn supports_get_derived_key(&self) -> Option<&dyn TeeCallGetDerivedKey> {
2051 Some(self)
2052 }
2053
2054 fn tee_type(&self) -> TeeType {
2055 TeeType::Snp
2057 }
2058 }
2059
2060 impl TeeCallGetDerivedKey for MockTeeCall {
2061 fn get_derived_key(
2062 &self,
2063 policy: KeyDerivationPolicy,
2064 ) -> Result<[u8; 32], tee_call::Error> {
2065 let mut key: [u8; HW_DERIVED_KEY_LENGTH] = [0xab; HW_DERIVED_KEY_LENGTH];
2067
2068 let tcb_version = match policy.svn {
2070 tee_call::KeyDerivationSvn::Snp { tcb_version } => tcb_version,
2071 tee_call::KeyDerivationSvn::Tdx { .. } => 0,
2072 };
2073 let tcb = tcb_version.to_le_bytes();
2074 for (i, b) in key.iter_mut().enumerate() {
2075 if policy.mix_measurement {
2076 *b ^= self.measurement[i] ^ tcb[i % tcb.len()];
2077 } else {
2078 *b ^= tcb[i % tcb.len()];
2079 }
2080 }
2081
2082 Ok(key)
2083 }
2084 }
2085
2086 pub struct MockTeeCallNoGetDerivedKey;
2088
2089 impl TeeCall for MockTeeCallNoGetDerivedKey {
2090 fn get_attestation_report(
2091 &self,
2092 report_data: &[u8; REPORT_DATA_SIZE],
2093 ) -> Result<GetAttestationReportResult, tee_call::Error> {
2094 let mut report =
2095 [0x6c; openhcl_attestation_protocol::igvm_attest::get::SNP_VM_REPORT_SIZE];
2096 report[..REPORT_DATA_SIZE].copy_from_slice(report_data);
2097
2098 Ok(GetAttestationReportResult {
2099 report: report.to_vec(),
2100 key_derivation_svn: None,
2101 })
2102 }
2103
2104 fn supports_get_derived_key(&self) -> Option<&dyn TeeCallGetDerivedKey> {
2105 None
2106 }
2107
2108 fn tee_type(&self) -> TeeType {
2109 TeeType::Snp
2111 }
2112 }
2113}
2114
2115#[cfg(test)]
2116mod tests {
2117 mod flush_fault;
2118
2119 use super::*;
2120 use crate::test_utils::MockTeeCallNoGetDerivedKey;
2121 use disk_backend::Disk;
2122 use disklayer_ram::ram_disk;
2123 use get_protocol::GSP_CLEARTEXT_MAX;
2124 use get_protocol::GspExtendedStatusFlags;
2125 use guest_emulation_device::IgvmAgentAction;
2126 use guest_emulation_device::IgvmAgentTestPlan;
2127 use guest_emulation_device::test_utilities::Event;
2128 use guest_emulation_device::test_utilities::TestGetResponses;
2129 use guest_emulation_transport::test_utilities::TestGet;
2130 use key_protector::AES_WRAPPED_AES_KEY_LENGTH;
2131 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestRequestType;
2132 use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::AttestationTpmVersion;
2133 use openhcl_attestation_protocol::vmgs::DEK_BUFFER_SIZE;
2134 use openhcl_attestation_protocol::vmgs::DekKp;
2135 use openhcl_attestation_protocol::vmgs::GSP_BUFFER_SIZE;
2136 use openhcl_attestation_protocol::vmgs::GspKp;
2137 use openhcl_attestation_protocol::vmgs::NUMBER_KP;
2138 use pal_async::DefaultDriver;
2139 use pal_async::async_test;
2140 use pal_async::task::Spawn;
2141 use std::collections::VecDeque;
2142 use test_utils::MockTeeCall;
2143 use test_with_tracing::test;
2144 use vmgs_format::EncryptionAlgorithm;
2145 use vmgs_format::FileId;
2146
2147 const ONE_MEGA_BYTE: u64 = 1024 * 1024;
2148
2149 fn test_attestation_config() -> AttestationVmConfig {
2150 AttestationVmConfig {
2151 current_time: None,
2152 root_cert_thumbprint: String::new(),
2153 console_enabled: false,
2154 interactive_console_enabled: false,
2155 ipmi_enabled: false,
2156 secure_boot: false,
2157 tpm_enabled: true,
2158 tpm_version: AttestationTpmVersion::V138,
2159 tpm_persisted: true,
2160 filtered_vpci_devices_allowed: false,
2161 vm_unique_id: String::new(),
2162 vmgs_provisioner: None,
2163 hardware_sealing_policy: HardwareSealingPolicy::None,
2164 }
2165 }
2166
2167 struct BootReportTee {
2170 inner: MockTeeCall,
2171 report_data: parking_lot::Mutex<Vec<[u8; REPORT_DATA_SIZE]>>,
2172 malformed: bool,
2173 fail_derivation: bool,
2174 derivation_calls: parking_lot::Mutex<usize>,
2175 }
2176
2177 impl BootReportTee {
2178 fn new() -> Self {
2179 Self {
2180 inner: MockTeeCall::new([0x12; 32]),
2181 report_data: parking_lot::Mutex::new(Vec::new()),
2182 malformed: false,
2183 fail_derivation: false,
2184 derivation_calls: parking_lot::Mutex::new(0),
2185 }
2186 }
2187 }
2188
2189 impl TeeCall for BootReportTee {
2190 fn get_attestation_report(
2191 &self,
2192 report_data: &[u8; REPORT_DATA_SIZE],
2193 ) -> Result<tee_call::GetAttestationReportResult, tee_call::Error> {
2194 self.report_data.lock().push(*report_data);
2195 let mut report = vec![0; 1184];
2196 report[..4].copy_from_slice(&3u32.to_le_bytes());
2197 report[0x50..0x50 + REPORT_DATA_SIZE].copy_from_slice(report_data);
2198 report[0x180..0x188].copy_from_slice(&self.inner.tcb_version.to_le_bytes());
2199 report[0x188] = 0x19;
2200 if self.malformed {
2201 report.truncate(1183);
2202 }
2203 Ok(tee_call::GetAttestationReportResult {
2204 report,
2205 key_derivation_svn: Some(tee_call::KeyDerivationSvn::Snp {
2206 tcb_version: self.inner.tcb_version,
2207 }),
2208 })
2209 }
2210
2211 fn supports_get_derived_key(&self) -> Option<&dyn tee_call::TeeCallGetDerivedKey> {
2212 Some(self)
2213 }
2214
2215 fn tee_type(&self) -> TeeType {
2216 TeeType::Snp
2217 }
2218 }
2219
2220 impl tee_call::TeeCallGetDerivedKey for BootReportTee {
2221 fn get_derived_key(
2222 &self,
2223 policy: KeyDerivationPolicy,
2224 ) -> Result<[u8; 32], tee_call::Error> {
2225 *self.derivation_calls.lock() += 1;
2226 if self.fail_derivation {
2227 return Err(tee_call::Error::AllZeroKey);
2228 }
2229 self.inner
2230 .supports_get_derived_key()
2231 .unwrap()
2232 .get_derived_key(policy)
2233 }
2234 }
2235
2236 struct FirstDerivationMigrationTee {
2240 source: BootReportTee,
2241 destination: BootReportTee,
2242 derivation_policies: parking_lot::Mutex<Vec<KeyDerivationPolicy>>,
2243 }
2244
2245 impl FirstDerivationMigrationTee {
2246 fn new() -> Self {
2247 let mut destination = BootReportTee::new();
2248 destination.inner.update_measurement([0x34; 32]);
2252 Self {
2253 source: BootReportTee::new(),
2254 destination,
2255 derivation_policies: parking_lot::Mutex::new(Vec::new()),
2256 }
2257 }
2258 }
2259
2260 impl TeeCall for FirstDerivationMigrationTee {
2261 fn get_attestation_report(
2262 &self,
2263 report_data: &[u8; REPORT_DATA_SIZE],
2264 ) -> Result<tee_call::GetAttestationReportResult, tee_call::Error> {
2265 assert!(
2266 self.source.report_data.lock().is_empty(),
2267 "extra boot report"
2268 );
2269 assert!(self.derivation_policies.lock().is_empty());
2270 assert_eq!(*self.source.derivation_calls.lock(), 0);
2271 assert_eq!(*self.destination.derivation_calls.lock(), 0);
2272 self.source.get_attestation_report(report_data)
2273 }
2274
2275 fn supports_get_derived_key(&self) -> Option<&dyn tee_call::TeeCallGetDerivedKey> {
2276 Some(self)
2277 }
2278
2279 fn tee_type(&self) -> TeeType {
2280 TeeType::Snp
2281 }
2282 }
2283
2284 impl tee_call::TeeCallGetDerivedKey for FirstDerivationMigrationTee {
2285 fn get_derived_key(
2286 &self,
2287 policy: KeyDerivationPolicy,
2288 ) -> Result<[u8; 32], tee_call::Error> {
2289 assert_eq!(&*self.source.report_data.lock(), &[[0; REPORT_DATA_SIZE]]);
2290 assert!(self.destination.report_data.lock().is_empty());
2291 self.derivation_policies.lock().push(policy);
2292 if !matches!(policy.svn, tee_call::KeyDerivationSvn::Snp { tcb_version }
2296 if tcb_version == self.destination.inner.tcb_version)
2297 {
2298 return Err(tee_call::Error::AllZeroKey);
2299 }
2300 self.destination
2301 .supports_get_derived_key()
2302 .unwrap()
2303 .get_derived_key(policy)
2304 }
2305 }
2306
2307 fn new_test_file() -> Disk {
2308 ram_disk(4 * ONE_MEGA_BYTE, false).unwrap()
2309 }
2310
2311 struct SequencedBootReportTee {
2314 inner: BootReportTee,
2315 report_svns: parking_lot::Mutex<VecDeque<u64>>,
2316 }
2317
2318 impl TeeCall for SequencedBootReportTee {
2319 fn get_attestation_report(
2320 &self,
2321 report_data: &[u8; REPORT_DATA_SIZE],
2322 ) -> Result<tee_call::GetAttestationReportResult, tee_call::Error> {
2323 let tcb_version = self
2324 .report_svns
2325 .lock()
2326 .pop_front()
2327 .expect("unexpected extra boot report acquisition");
2328 let mut result = self.inner.get_attestation_report(report_data)?;
2329 result.report[0x180..0x188].copy_from_slice(&tcb_version.to_le_bytes());
2330 result.key_derivation_svn = Some(tee_call::KeyDerivationSvn::Snp { tcb_version });
2331 Ok(result)
2332 }
2333
2334 fn supports_get_derived_key(&self) -> Option<&dyn tee_call::TeeCallGetDerivedKey> {
2335 self.inner.supports_get_derived_key()
2336 }
2337
2338 fn tee_type(&self) -> TeeType {
2339 self.inner.tee_type()
2340 }
2341 }
2342
2343 async fn new_formatted_vmgs() -> Vmgs {
2344 let disk = new_test_file();
2345
2346 let mut vmgs = Vmgs::format_new(disk, None).await.unwrap();
2347
2348 assert!(
2349 key_protector_is_empty(&mut vmgs).await,
2350 "Newly formatted VMGS should have an empty key protector"
2351 );
2352 assert!(
2353 key_protector_by_id_is_empty(&mut vmgs).await,
2354 "Newly formatted VMGS should have an empty key protector by id"
2355 );
2356
2357 vmgs
2358 }
2359
2360 async fn key_protector_is_empty(vmgs: &mut Vmgs) -> bool {
2361 let key_protector = vmgs::read_key_protector(vmgs, AES_WRAPPED_AES_KEY_LENGTH)
2362 .await
2363 .unwrap();
2364
2365 key_protector.as_bytes().iter().all(|&b| b == 0)
2366 }
2367
2368 async fn key_protector_by_id_is_empty(vmgs: &mut Vmgs) -> bool {
2369 vmgs::read_key_protector_by_id(vmgs)
2370 .await
2371 .is_err_and(|err| {
2372 matches!(
2373 err,
2374 vmgs::ReadFromVmgsError::EntryNotFound(FileId::VM_UNIQUE_ID)
2375 )
2376 })
2377 }
2378
2379 async fn hardware_key_protector_is_empty(vmgs: &mut Vmgs) -> bool {
2380 vmgs::read_hardware_key_protector(vmgs)
2381 .await
2382 .is_err_and(|err| {
2383 matches!(
2384 err,
2385 vmgs::ReadFromVmgsError::EntryNotFound(FileId::HW_KEY_PROTECTOR)
2386 )
2387 })
2388 }
2389
2390 fn new_key_protector() -> KeyProtector {
2391 assert_eq!(NUMBER_KP, 2);
2393
2394 let ingress_dek = DekKp {
2395 dek_buffer: [1; DEK_BUFFER_SIZE],
2396 };
2397 let egress_dek = DekKp {
2398 dek_buffer: [2; DEK_BUFFER_SIZE],
2399 };
2400 let ingress_gsp = GspKp {
2401 gsp_length: GSP_BUFFER_SIZE as u32,
2402 gsp_buffer: [3; GSP_BUFFER_SIZE],
2403 };
2404 let egress_gsp = GspKp {
2405 gsp_length: GSP_BUFFER_SIZE as u32,
2406 gsp_buffer: [4; GSP_BUFFER_SIZE],
2407 };
2408 KeyProtector {
2409 dek: [ingress_dek, egress_dek],
2410 gsp: [ingress_gsp, egress_gsp],
2411 active_kp: 0,
2412 }
2413 }
2414
2415 fn new_key_protector_by_id(
2416 id_guid: Option<Guid>,
2417 ported: Option<u8>,
2418 found_id: bool,
2419 ) -> KeyProtectorById {
2420 let key_protector_by_id = openhcl_attestation_protocol::vmgs::KeyProtectorById {
2421 id_guid: id_guid.unwrap_or_else(Guid::new_random),
2422 ported: ported.unwrap_or(0),
2423 pad: [0; 3],
2424 };
2425
2426 KeyProtectorById {
2427 inner: key_protector_by_id,
2428 found_id,
2429 }
2430 }
2431
2432 async fn new_test_get(
2433 spawn: impl Spawn,
2434 enable_igvm_attest: bool,
2435 plan: Option<IgvmAgentTestPlan>,
2436 ) -> TestGet {
2437 if enable_igvm_attest {
2438 const TEST_DEVICE_MEMORY_SIZE: u64 = 64;
2439 let dev_test_mem = user_driver_emulated_mock::DeviceTestMemory::new(
2441 TEST_DEVICE_MEMORY_SIZE,
2442 true,
2443 "test-attest",
2444 );
2445
2446 let mut test_get = guest_emulation_transport::test_utilities::new_transport_pair(
2447 spawn,
2448 None,
2449 get_protocol::ProtocolVersion::NICKEL_REV2,
2450 Some(dev_test_mem.guest_memory()),
2451 plan,
2452 )
2453 .await;
2454
2455 test_get.client.set_gpa_allocator(dev_test_mem.dma_client());
2456
2457 test_get
2458 } else {
2459 guest_emulation_transport::test_utilities::new_transport_pair(
2460 spawn,
2461 None,
2462 get_protocol::ProtocolVersion::NICKEL_REV2,
2463 None,
2464 None,
2465 )
2466 .await
2467 }
2468 }
2469
2470 fn new_attestation_vm_config() -> AttestationVmConfig {
2471 AttestationVmConfig {
2472 current_time: None,
2473 root_cert_thumbprint: String::new(),
2474 console_enabled: false,
2475 interactive_console_enabled: false,
2476 ipmi_enabled: false,
2477 secure_boot: false,
2478 tpm_enabled: true,
2479 tpm_version: AttestationTpmVersion::V138,
2480 tpm_persisted: true,
2481 hardware_sealing_policy: HardwareSealingPolicy::None,
2482 filtered_vpci_devices_allowed: false,
2483 vm_unique_id: String::new(),
2484 vmgs_provisioner: None,
2485 }
2486 }
2487
2488 #[async_test]
2489 async fn do_nothing_without_derived_keys() {
2490 let mut vmgs = new_formatted_vmgs().await;
2491
2492 let mut key_protector = new_key_protector();
2493 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2494
2495 let key_protector_settings = KeyProtectorSettings {
2496 should_write_kp: false,
2497 use_gsp_by_id: false,
2498 use_hardware_unlock: false,
2499 decrypt_gsp_type: GspType::None,
2500 encrypt_gsp_type: GspType::None,
2501 };
2502
2503 let bios_guid = Guid::new_random();
2504
2505 unlock_vmgs_data_store(
2506 &mut vmgs,
2507 false,
2508 &mut key_protector,
2509 &mut key_protector_by_id,
2510 None,
2511 None,
2512 key_protector_settings,
2513 bios_guid,
2514 )
2515 .await
2516 .unwrap();
2517
2518 assert!(key_protector_is_empty(&mut vmgs).await);
2519 assert!(key_protector_by_id_is_empty(&mut vmgs).await);
2520
2521 let key_protector_settings = KeyProtectorSettings {
2523 should_write_kp: false,
2524 use_gsp_by_id: false,
2525 use_hardware_unlock: false,
2526 decrypt_gsp_type: GspType::None,
2527 encrypt_gsp_type: GspType::None,
2528 };
2529
2530 unlock_vmgs_data_store(
2532 &mut vmgs,
2533 true,
2534 &mut key_protector,
2535 &mut key_protector_by_id,
2536 None,
2537 None,
2538 key_protector_settings,
2539 bios_guid,
2540 )
2541 .await
2542 .unwrap();
2543
2544 assert!(key_protector_is_empty(&mut vmgs).await);
2545 assert!(key_protector_by_id_is_empty(&mut vmgs).await);
2546 }
2547
2548 #[async_test]
2549 async fn provision_vmgs_and_rotate_keys() {
2550 let mut vmgs = new_formatted_vmgs().await;
2551
2552 let mut key_protector = new_key_protector();
2553 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2554
2555 let ingress = [1; AES_GCM_KEY_LENGTH];
2556 let egress = [2; AES_GCM_KEY_LENGTH];
2557 let derived_keys = Keys {
2558 ingress,
2559 decrypt_egress: None,
2560 encrypt_egress: egress,
2561 };
2562
2563 let key_protector_settings = KeyProtectorSettings {
2564 should_write_kp: true,
2565 use_gsp_by_id: true,
2566 use_hardware_unlock: false,
2567 decrypt_gsp_type: GspType::GspById,
2568 encrypt_gsp_type: GspType::GspById,
2569 };
2570
2571 let bios_guid = Guid::new_random();
2572
2573 unlock_vmgs_data_store(
2576 &mut vmgs,
2577 false,
2578 &mut key_protector,
2579 &mut key_protector_by_id,
2580 None,
2581 Some(derived_keys),
2582 key_protector_settings,
2583 bios_guid,
2584 )
2585 .await
2586 .unwrap();
2587
2588 vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
2590
2591 vmgs.unlock_with_encryption_key(&egress).await.unwrap();
2593 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(0));
2595
2596 assert!(!key_protector_is_empty(&mut vmgs).await);
2598 assert!(!key_protector_by_id_is_empty(&mut vmgs).await);
2599
2600 let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
2601 .await
2602 .unwrap();
2603 assert_eq!(found_key_protector.as_bytes(), key_protector.as_bytes());
2604
2605 let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
2606 assert_eq!(
2607 found_key_protector_by_id.as_bytes(),
2608 key_protector_by_id.inner.as_bytes()
2609 );
2610
2611 let new_egress = [3; AES_GCM_KEY_LENGTH];
2613
2614 let mut new_key_protector = new_key_protector();
2615 let mut new_key_protector_by_id = new_key_protector_by_id(None, None, false);
2616
2617 let key_protector_settings = KeyProtectorSettings {
2618 should_write_kp: true,
2619 use_gsp_by_id: true,
2620 use_hardware_unlock: false,
2621 decrypt_gsp_type: GspType::GspById,
2622 encrypt_gsp_type: GspType::GspById,
2623 };
2624
2625 let derived_keys = Keys {
2627 ingress: egress,
2628 decrypt_egress: None,
2629 encrypt_egress: new_egress,
2630 };
2631
2632 unlock_vmgs_data_store(
2633 &mut vmgs,
2634 true,
2635 &mut new_key_protector,
2636 &mut new_key_protector_by_id,
2637 None,
2638 Some(derived_keys),
2639 key_protector_settings,
2640 bios_guid,
2641 )
2642 .await
2643 .unwrap();
2644
2645 vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
2647 vmgs.unlock_with_encryption_key(&egress).await.unwrap_err();
2649
2650 vmgs.unlock_with_encryption_key(&new_egress).await.unwrap();
2652 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2654
2655 let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
2656 .await
2657 .unwrap();
2658 assert_eq!(found_key_protector.as_bytes(), new_key_protector.as_bytes());
2659
2660 let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
2661 assert_eq!(
2662 found_key_protector_by_id.as_bytes(),
2663 new_key_protector_by_id.inner.as_bytes()
2664 );
2665 }
2666
2667 #[async_test]
2668 async fn unlock_previously_encrypted_vmgs_with_ingress_key() {
2669 let mut vmgs = new_formatted_vmgs().await;
2670
2671 let mut key_protector = new_key_protector();
2672 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2673
2674 let ingress = [1; AES_GCM_KEY_LENGTH];
2675 let egress = [2; AES_GCM_KEY_LENGTH];
2676
2677 let derived_keys = Keys {
2678 ingress,
2679 decrypt_egress: None,
2680 encrypt_egress: egress,
2681 };
2682
2683 vmgs.update_encryption_key(&ingress, EncryptionAlgorithm::AES_GCM)
2684 .await
2685 .unwrap();
2686
2687 vmgs.unlock_with_encryption_key(&ingress).await.unwrap();
2689 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(0));
2690
2691 let key_protector_settings = KeyProtectorSettings {
2692 should_write_kp: true,
2693 use_gsp_by_id: true,
2694 use_hardware_unlock: false,
2695 decrypt_gsp_type: GspType::GspById,
2696 encrypt_gsp_type: GspType::GspById,
2697 };
2698
2699 let bios_guid = Guid::new_random();
2700
2701 unlock_vmgs_data_store(
2702 &mut vmgs,
2703 true,
2704 &mut key_protector,
2705 &mut key_protector_by_id,
2706 None,
2707 Some(derived_keys),
2708 key_protector_settings,
2709 bios_guid,
2710 )
2711 .await
2712 .unwrap();
2713
2714 vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
2716 vmgs.unlock_with_encryption_key(&egress).await.unwrap();
2717 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2719
2720 let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
2722 .await
2723 .unwrap();
2724 assert_eq!(found_key_protector.as_bytes(), key_protector.as_bytes());
2725
2726 let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
2727 assert_eq!(
2728 found_key_protector_by_id.as_bytes(),
2729 key_protector_by_id.inner.as_bytes()
2730 );
2731 }
2732
2733 #[async_test]
2734 async fn failed_to_persist_ingress_key_so_use_egress_key_to_unlock_vmgs() {
2735 let mut vmgs = new_formatted_vmgs().await;
2736
2737 let mut key_protector = new_key_protector();
2738 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2739
2740 let ingress = [1; AES_GCM_KEY_LENGTH];
2741 let decrypt_egress = [2; AES_GCM_KEY_LENGTH];
2742 let encrypt_egress = [3; AES_GCM_KEY_LENGTH];
2743
2744 let derived_keys = Keys {
2745 ingress,
2746 decrypt_egress: Some(decrypt_egress),
2747 encrypt_egress,
2748 };
2749
2750 vmgs.test_add_new_encryption_key(&decrypt_egress, EncryptionAlgorithm::AES_GCM)
2752 .await
2753 .unwrap();
2754 let egress_key_index = vmgs.test_get_active_datastore_key_index().unwrap();
2755 assert_eq!(egress_key_index, 0);
2756
2757 vmgs.unlock_with_encryption_key(&decrypt_egress)
2758 .await
2759 .unwrap();
2760 let found_egress_key_index = vmgs.test_get_active_datastore_key_index().unwrap();
2761 assert_eq!(found_egress_key_index, egress_key_index);
2762
2763 vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
2765
2766 let key_protector_settings = KeyProtectorSettings {
2767 should_write_kp: true,
2768 use_gsp_by_id: true,
2769 use_hardware_unlock: false,
2770 decrypt_gsp_type: GspType::GspById,
2771 encrypt_gsp_type: GspType::GspById,
2772 };
2773
2774 let bios_guid = Guid::new_random();
2775
2776 unlock_vmgs_data_store(
2777 &mut vmgs,
2778 true,
2779 &mut key_protector,
2780 &mut key_protector_by_id,
2781 None,
2782 Some(derived_keys),
2783 key_protector_settings,
2784 bios_guid,
2785 )
2786 .await
2787 .unwrap();
2788
2789 vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
2791
2792 vmgs.unlock_with_encryption_key(&decrypt_egress)
2794 .await
2795 .unwrap_err();
2796
2797 vmgs.unlock_with_encryption_key(&encrypt_egress)
2799 .await
2800 .unwrap();
2801 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2802
2803 let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
2805 .await
2806 .unwrap();
2807 assert_eq!(found_key_protector.as_bytes(), key_protector.as_bytes());
2808
2809 let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
2810 assert_eq!(
2811 found_key_protector_by_id.as_bytes(),
2812 key_protector_by_id.inner.as_bytes()
2813 );
2814 }
2815
2816 #[async_test]
2817 async fn fail_to_unlock_vmgs_with_existing_ingress_key() {
2818 let mut vmgs = new_formatted_vmgs().await;
2819
2820 let mut key_protector = new_key_protector();
2821 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2822
2823 let ingress = [1; AES_GCM_KEY_LENGTH];
2824
2825 let derived_keys = Keys {
2827 ingress,
2828 decrypt_egress: None,
2829 encrypt_egress: ingress,
2830 };
2831
2832 let additional_key = [2; AES_GCM_KEY_LENGTH];
2834 let yet_another_key = [3; AES_GCM_KEY_LENGTH];
2835
2836 vmgs.test_add_new_encryption_key(&additional_key, EncryptionAlgorithm::AES_GCM)
2837 .await
2838 .unwrap();
2839 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(0));
2840
2841 vmgs.test_add_new_encryption_key(&yet_another_key, EncryptionAlgorithm::AES_GCM)
2842 .await
2843 .unwrap();
2844 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2845
2846 let key_protector_settings = KeyProtectorSettings {
2847 should_write_kp: true,
2848 use_gsp_by_id: true,
2849 use_hardware_unlock: false,
2850 decrypt_gsp_type: GspType::GspById,
2851 encrypt_gsp_type: GspType::GspById,
2852 };
2853
2854 let bios_guid = Guid::new_random();
2855
2856 let unlock_result = unlock_vmgs_data_store(
2857 &mut vmgs,
2858 true,
2859 &mut key_protector,
2860 &mut key_protector_by_id,
2861 None,
2862 Some(derived_keys),
2863 key_protector_settings,
2864 bios_guid,
2865 )
2866 .await;
2867 assert!(unlock_result.is_err());
2868 assert_eq!(
2869 unlock_result.unwrap_err().to_string(),
2870 "failed to unlock vmgs with the existing ingress key".to_string()
2871 );
2872 }
2873
2874 #[async_test]
2875 async fn fail_to_unlock_vmgs_with_new_ingress_key() {
2876 let mut vmgs = new_formatted_vmgs().await;
2877
2878 let mut key_protector = new_key_protector();
2879 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2880
2881 let derived_keys = Keys {
2882 ingress: [1; AES_GCM_KEY_LENGTH],
2883 decrypt_egress: None,
2884 encrypt_egress: [2; AES_GCM_KEY_LENGTH],
2885 };
2886
2887 let additional_key = [3; AES_GCM_KEY_LENGTH];
2889 let yet_another_key = [4; AES_GCM_KEY_LENGTH];
2890
2891 vmgs.test_add_new_encryption_key(&additional_key, EncryptionAlgorithm::AES_GCM)
2892 .await
2893 .unwrap();
2894 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(0));
2895
2896 vmgs.test_add_new_encryption_key(&yet_another_key, EncryptionAlgorithm::AES_GCM)
2897 .await
2898 .unwrap();
2899 assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2900
2901 let key_protector_settings = KeyProtectorSettings {
2902 should_write_kp: true,
2903 use_gsp_by_id: true,
2904 use_hardware_unlock: false,
2905 decrypt_gsp_type: GspType::GspById,
2906 encrypt_gsp_type: GspType::GspById,
2907 };
2908
2909 let bios_guid = Guid::new_random();
2910
2911 let unlock_result = unlock_vmgs_data_store(
2912 &mut vmgs,
2913 true,
2914 &mut key_protector,
2915 &mut key_protector_by_id,
2916 None,
2917 Some(derived_keys),
2918 key_protector_settings,
2919 bios_guid,
2920 )
2921 .await;
2922 assert!(unlock_result.is_err());
2923 assert_eq!(
2924 unlock_result.unwrap_err().to_string(),
2925 "failed to unlock vmgs with the existing ingress key".to_string()
2926 );
2927 }
2928
2929 #[async_test]
2930 async fn get_derived_keys_using_id() {
2931 let bios_guid = Guid::new_random();
2932
2933 let gsp_response_by_id = GuestStateProtectionById {
2934 seed: guest_emulation_transport::api::GspCleartextContent {
2935 length: GSP_CLEARTEXT_MAX,
2936 buffer: [1; GSP_CLEARTEXT_MAX as usize * 2],
2937 },
2938 extended_status_flags: GspExtendedStatusFlags::from_bits(0),
2939 };
2940
2941 let mut key_protector_by_id =
2944 new_key_protector_by_id(Some(Guid::new_zeroed()), None, false);
2945 let derived_keys =
2946 get_derived_keys_by_id(&mut key_protector_by_id, bios_guid, gsp_response_by_id)
2947 .unwrap();
2948
2949 assert_eq!(derived_keys.ingress, derived_keys.encrypt_egress);
2950
2951 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2954 let derived_keys =
2955 get_derived_keys_by_id(&mut key_protector_by_id, bios_guid, gsp_response_by_id)
2956 .unwrap();
2957
2958 assert_ne!(derived_keys.ingress, derived_keys.encrypt_egress);
2959
2960 let gsp_response_by_id_with_0_length_seed = GuestStateProtectionById {
2962 seed: guest_emulation_transport::api::GspCleartextContent {
2963 length: 0,
2964 buffer: [1; GSP_CLEARTEXT_MAX as usize * 2],
2965 },
2966 extended_status_flags: GspExtendedStatusFlags::from_bits(0),
2967 };
2968
2969 let derived_keys_response = get_derived_keys_by_id(
2970 &mut key_protector_by_id,
2971 bios_guid,
2972 gsp_response_by_id_with_0_length_seed,
2973 );
2974 assert!(derived_keys_response.is_err());
2975 assert_eq!(
2976 derived_keys_response.unwrap_err().to_string(),
2977 "failed to derive an egress key based on current vm bios guid".to_string()
2978 );
2979 }
2980
2981 #[async_test]
2982 async fn pass_through_persist_all_key_protectors() {
2983 let mut vmgs = new_formatted_vmgs().await;
2984 let mut key_protector = new_key_protector();
2985 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2986 let bios_guid = Guid::new_random();
2987
2988 let kp_copy = key_protector.as_bytes().to_vec();
2990 let active_kp_copy = key_protector.active_kp;
2991
2992 let key_protector_settings = KeyProtectorSettings {
2994 should_write_kp: true,
2995 use_gsp_by_id: true,
2996 use_hardware_unlock: true,
2997 decrypt_gsp_type: GspType::GspById,
2998 encrypt_gsp_type: GspType::GspById,
2999 };
3000 persist_all_key_protectors(
3001 &mut vmgs,
3002 &mut key_protector,
3003 &mut key_protector_by_id,
3004 Some(&HardwareKeyProtectorV3::new_zeroed()),
3005 bios_guid,
3006 key_protector_settings,
3007 )
3008 .await
3009 .unwrap();
3010
3011 assert!(key_protector_is_empty(&mut vmgs).await);
3012 assert!(key_protector_by_id_is_empty(&mut vmgs).await);
3013
3014 assert_eq!(active_kp_copy, key_protector.active_kp);
3016 assert_eq!(kp_copy.as_slice(), key_protector.as_bytes());
3017 }
3018
3019 #[async_test]
3020 async fn hardware_sealing_first_boot_creates_hwkp_and_encrypts_vmgs(driver: DefaultDriver) {
3021 let mut vmgs = new_formatted_vmgs().await;
3022 let mut key_protector = KeyProtector::new_zeroed();
3024 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
3025 let bios_guid = Guid::new_random();
3026
3027 let get_pair = guest_emulation_transport::test_utilities::new_transport_pair(
3029 driver,
3030 None,
3031 get_protocol::ProtocolVersion::NICKEL_REV2,
3032 None,
3033 None,
3034 )
3035 .await;
3036
3037 let mock_tee_call = MockTeeCall::new([0x8a; 32]);
3038
3039 let derived = get_derived_keys(
3041 &get_pair.client,
3042 Some(&mock_tee_call),
3043 &mut vmgs,
3044 &mut key_protector,
3045 &mut key_protector_by_id,
3046 bios_guid,
3047 &AttestationVmConfig {
3048 current_time: None,
3049 root_cert_thumbprint: String::new(),
3050 console_enabled: false,
3051 interactive_console_enabled: false,
3052 ipmi_enabled: false,
3053 secure_boot: false,
3054 tpm_enabled: false,
3055 tpm_version: AttestationTpmVersion::V138,
3056 tpm_persisted: false,
3057 hardware_sealing_policy: HardwareSealingPolicy::Hash,
3058 filtered_vpci_devices_allowed: true,
3059 vm_unique_id: String::new(),
3060 vmgs_provisioner: None,
3061 },
3062 false,
3063 None,
3064 None,
3065 Some(KeyDerivationPolicy {
3066 svn: tee_call::KeyDerivationSvn::Snp {
3067 tcb_version: 0x1234,
3068 },
3069 mix_measurement: true,
3070 }),
3071 GuestStateEncryptionPolicy::HardwareSealing,
3072 true,
3073 true,
3074 false,
3075 )
3076 .await
3077 .unwrap();
3078
3079 assert!(derived.derived_keys.is_some());
3081 assert!(derived.hardware_key_protector.is_some());
3082
3083 let egress_key = derived.derived_keys.as_ref().unwrap().encrypt_egress;
3085
3086 unlock_vmgs_data_store(
3088 &mut vmgs,
3089 false,
3090 &mut key_protector,
3091 &mut key_protector_by_id,
3092 derived.hardware_key_protector,
3093 derived.derived_keys,
3094 derived.key_protector_settings,
3095 bios_guid,
3096 )
3097 .await
3098 .unwrap();
3099
3100 vmgs.unlock_with_encryption_key(&egress_key).await.unwrap();
3102
3103 vmgs.unlock_with_encryption_key(&[0; AES_GCM_KEY_LENGTH])
3105 .await
3106 .unwrap_err();
3107 }
3108
3109 #[async_test]
3110 async fn hardware_sealing_recovery_uses_hwkp_v2_when_encrypted(driver: DefaultDriver) {
3111 let mut vmgs = new_formatted_vmgs().await;
3112
3113 let bootstrap = [0x33; AES_GCM_KEY_LENGTH];
3115 vmgs.test_add_new_encryption_key(&bootstrap, EncryptionAlgorithm::AES_GCM)
3116 .await
3117 .unwrap();
3118
3119 let mut key_protector = new_key_protector();
3120 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
3121 let bios_guid = Guid::new_random();
3122
3123 let mock_tee_call = MockTeeCall::new([0x8a; 32]);
3125
3126 let hdk = HardwareDerivedKeys::derive_key(
3127 mock_tee_call.supports_get_derived_key().unwrap(),
3128 &AttestationVmConfig {
3129 current_time: None,
3130 root_cert_thumbprint: String::new(),
3131 console_enabled: false,
3132 interactive_console_enabled: false,
3133 ipmi_enabled: false,
3134 secure_boot: false,
3135 tpm_enabled: false,
3136 tpm_version: AttestationTpmVersion::V138,
3137 tpm_persisted: false,
3138 hardware_sealing_policy: HardwareSealingPolicy::Hash,
3139 filtered_vpci_devices_allowed: true,
3140 vm_unique_id: String::new(),
3141 vmgs_provisioner: None,
3142 },
3143 KeyDerivationPolicy {
3144 svn: tee_call::KeyDerivationSvn::Snp {
3145 tcb_version: 0x1234,
3146 },
3147 mix_measurement: true,
3148 },
3149 )
3150 .unwrap();
3151 let hwkp = hardware_key_sealing::seal_key(&hdk, &bootstrap).unwrap();
3152 vmgs::write_hardware_key_protector(&hwkp, &mut vmgs)
3153 .await
3154 .unwrap();
3155
3156 let get_pair = guest_emulation_transport::test_utilities::new_transport_pair(
3159 driver,
3160 None,
3161 get_protocol::ProtocolVersion::NICKEL_REV2,
3162 None,
3163 None,
3164 )
3165 .await;
3166
3167 let derived = get_derived_keys(
3168 &get_pair.client,
3169 Some(&mock_tee_call),
3170 &mut vmgs,
3171 &mut key_protector,
3172 &mut key_protector_by_id,
3173 bios_guid,
3174 &AttestationVmConfig {
3175 current_time: None,
3176 root_cert_thumbprint: String::new(),
3177 console_enabled: false,
3178 interactive_console_enabled: false,
3179 ipmi_enabled: false,
3180 secure_boot: false,
3181 tpm_enabled: false,
3182 tpm_version: AttestationTpmVersion::V138,
3183 tpm_persisted: false,
3184 hardware_sealing_policy: HardwareSealingPolicy::Hash,
3185 filtered_vpci_devices_allowed: true,
3186 vm_unique_id: String::new(),
3187 vmgs_provisioner: None,
3188 },
3189 true,
3190 None,
3191 None,
3192 Some(KeyDerivationPolicy {
3193 svn: tee_call::KeyDerivationSvn::Snp {
3194 tcb_version: 0x1234,
3195 },
3196 mix_measurement: true,
3197 }),
3198 GuestStateEncryptionPolicy::HardwareSealing,
3199 true,
3200 true,
3201 false,
3202 )
3203 .await
3204 .unwrap();
3205
3206 let keys = derived.derived_keys.unwrap();
3208 assert_eq!(keys.ingress, bootstrap);
3209 assert_ne!(keys.encrypt_egress, keys.ingress);
3210 }
3211
3212 #[async_test]
3220 async fn hardware_sealing_skips_gsp_state_refresh(driver: DefaultDriver) {
3221 let mut vmgs = new_formatted_vmgs().await;
3222 let mut key_protector = KeyProtector::new_zeroed();
3223 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
3224 let bios_guid = Guid::new_random();
3225
3226 let get_pair = guest_emulation_transport::test_utilities::new_transport_pair(
3229 driver,
3230 None,
3231 get_protocol::ProtocolVersion::NICKEL_REV2,
3232 None,
3233 None,
3234 )
3235 .await;
3236
3237 let mock_tee_call = MockTeeCall::new([0x8a; 32]);
3238
3239 let derived = get_derived_keys(
3240 &get_pair.client,
3241 Some(&mock_tee_call),
3242 &mut vmgs,
3243 &mut key_protector,
3244 &mut key_protector_by_id,
3245 bios_guid,
3246 &AttestationVmConfig {
3247 current_time: None,
3248 root_cert_thumbprint: String::new(),
3249 console_enabled: false,
3250 interactive_console_enabled: false,
3251 ipmi_enabled: false,
3252 secure_boot: false,
3253 tpm_enabled: false,
3254 tpm_version: AttestationTpmVersion::V138,
3255 tpm_persisted: false,
3256 hardware_sealing_policy: HardwareSealingPolicy::Hash,
3257 filtered_vpci_devices_allowed: true,
3258 vm_unique_id: String::new(),
3259 vmgs_provisioner: None,
3260 },
3261 false,
3262 None,
3263 None,
3264 Some(KeyDerivationPolicy {
3265 svn: tee_call::KeyDerivationSvn::Snp {
3266 tcb_version: 0x1234,
3267 },
3268 mix_measurement: true,
3269 }),
3270 GuestStateEncryptionPolicy::HardwareSealing,
3271 true,
3272 true,
3273 false,
3274 )
3275 .await
3276 .unwrap();
3277
3278 assert!(!derived.gsp_extended_status_flags.state_refresh_request());
3281 }
3282
3283 #[async_test]
3288 async fn non_sealing_propagates_gsp_state_refresh(driver: DefaultDriver) {
3289 let mut vmgs = new_formatted_vmgs().await;
3290 let mut key_protector = KeyProtector::new_zeroed();
3291 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
3292 let bios_guid = Guid::new_random();
3293
3294 let gsp_response = TestGetResponses::new(Event::Response(
3298 get_protocol::GuestStateProtectionResponse {
3299 message_header: get_protocol::HeaderGeneric::new(
3300 get_protocol::HostRequests::GUEST_STATE_PROTECTION,
3301 ),
3302 encrypted_gsp: get_protocol::GspCiphertextContent::new_zeroed(),
3303 decrypted_gsp: [get_protocol::GspCleartextContent::new_zeroed();
3304 get_protocol::NUMBER_GSP as usize],
3305 extended_status_flags: GspExtendedStatusFlags::new()
3306 .with_state_refresh_request(true),
3307 }
3308 .as_bytes()
3309 .to_vec(),
3310 ));
3311 let gsp_by_id_response = TestGetResponses::new(Event::Response(
3312 get_protocol::GuestStateProtectionByIdResponse {
3313 message_header: get_protocol::HeaderGeneric::new(
3314 get_protocol::HostRequests::GUEST_STATE_PROTECTION_BY_ID,
3315 ),
3316 seed: get_protocol::GspCleartextContent::new_zeroed(),
3317 extended_status_flags: GspExtendedStatusFlags::new().with_no_registry_file(true),
3318 }
3319 .as_bytes()
3320 .to_vec(),
3321 ));
3322
3323 let get_pair = guest_emulation_transport::test_utilities::new_transport_pair(
3324 driver,
3325 Some(vec![gsp_response, gsp_by_id_response]),
3326 get_protocol::ProtocolVersion::NICKEL_REV2,
3327 None,
3328 None,
3329 )
3330 .await;
3331
3332 let derived = get_derived_keys(
3333 &get_pair.client,
3334 None,
3335 &mut vmgs,
3336 &mut key_protector,
3337 &mut key_protector_by_id,
3338 bios_guid,
3339 &new_attestation_vm_config(),
3340 false,
3341 None,
3342 None,
3343 None,
3344 GuestStateEncryptionPolicy::Auto,
3345 false,
3346 false,
3347 false,
3348 )
3349 .await
3350 .unwrap();
3351
3352 assert!(derived.gsp_extended_status_flags.state_refresh_request());
3355 }
3356
3357 #[async_test]
3358 async fn persist_all_key_protectors_write_key_protector_by_id() {
3359 let mut vmgs = new_formatted_vmgs().await;
3360 let mut key_protector = new_key_protector();
3361 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
3362 let bios_guid = Guid::new_random();
3363
3364 let kp_copy = key_protector.as_bytes().to_vec();
3366 let active_kp_copy = key_protector.active_kp;
3367
3368 let key_protector_settings = KeyProtectorSettings {
3370 should_write_kp: false,
3371 use_gsp_by_id: true,
3372 use_hardware_unlock: false,
3373 decrypt_gsp_type: GspType::GspById,
3374 encrypt_gsp_type: GspType::GspById,
3375 };
3376 persist_all_key_protectors(
3377 &mut vmgs,
3378 &mut key_protector,
3379 &mut key_protector_by_id,
3380 None,
3381 bios_guid,
3382 key_protector_settings,
3383 )
3384 .await
3385 .unwrap();
3386
3387 assert!(key_protector_is_empty(&mut vmgs).await);
3389 assert!(!key_protector_by_id_is_empty(&mut vmgs).await);
3390
3391 let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
3392 assert_eq!(
3393 found_key_protector_by_id.as_bytes(),
3394 key_protector_by_id.inner.as_bytes()
3395 );
3396
3397 assert_eq!(kp_copy.as_slice(), key_protector.as_bytes());
3399 assert_eq!(active_kp_copy, key_protector.active_kp);
3400 }
3401
3402 #[async_test]
3403 async fn persist_all_key_protectors_remove_ingress_kp() {
3404 let mut vmgs = new_formatted_vmgs().await;
3405 let mut key_protector = new_key_protector();
3406 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
3407 let bios_guid = Guid::new_random();
3408
3409 let active_kp_copy = key_protector.active_kp;
3411
3412 let key_protector_settings = KeyProtectorSettings {
3415 should_write_kp: true,
3416 use_gsp_by_id: false,
3417 use_hardware_unlock: false,
3418 decrypt_gsp_type: GspType::None,
3419 encrypt_gsp_type: GspType::None,
3420 };
3421 persist_all_key_protectors(
3422 &mut vmgs,
3423 &mut key_protector,
3424 &mut key_protector_by_id,
3425 None,
3426 bios_guid,
3427 key_protector_settings,
3428 )
3429 .await
3430 .unwrap();
3431
3432 assert!(!key_protector_is_empty(&mut vmgs).await);
3433 assert!(key_protector_by_id_is_empty(&mut vmgs).await);
3434
3435 let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
3437 .await
3438 .unwrap();
3439
3440 assert!(
3441 found_key_protector.dek[active_kp_copy as usize]
3442 .dek_buffer
3443 .iter()
3444 .all(|&b| b == 0),
3445 );
3446 assert_eq!(
3447 found_key_protector.gsp[active_kp_copy as usize].gsp_length,
3448 0
3449 );
3450 assert_eq!(found_key_protector.active_kp, active_kp_copy + 1);
3451 }
3452
3453 #[async_test]
3454 async fn persist_all_key_protectors_mark_key_protector_by_id_as_not_in_use() {
3455 let mut vmgs = new_formatted_vmgs().await;
3456 let mut key_protector = new_key_protector();
3457 let mut key_protector_by_id = new_key_protector_by_id(None, None, true);
3458 let bios_guid = Guid::new_random();
3459
3460 let key_protector_settings = KeyProtectorSettings {
3463 should_write_kp: true,
3464 use_gsp_by_id: false,
3465 use_hardware_unlock: true,
3466 decrypt_gsp_type: GspType::None,
3467 encrypt_gsp_type: GspType::None,
3468 };
3469
3470 persist_all_key_protectors(
3471 &mut vmgs,
3472 &mut key_protector,
3473 &mut key_protector_by_id,
3474 Some(&HardwareKeyProtectorV3::new_zeroed()),
3475 bios_guid,
3476 key_protector_settings,
3477 )
3478 .await
3479 .unwrap();
3480
3481 assert!(key_protector_is_empty(&mut vmgs).await);
3482 assert!(!key_protector_by_id_is_empty(&mut vmgs).await);
3483
3484 let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
3486 assert_eq!(found_key_protector_by_id.ported, 1);
3487 assert_eq!(
3488 found_key_protector_by_id.id_guid,
3489 key_protector_by_id.inner.id_guid
3490 );
3491 }
3492
3493 #[async_test]
3496 async fn init_sec_required_stateless_sealing_enrolls_and_rotates(driver: DefaultDriver) {
3497 let get_pair = new_test_get(driver, false, None).await;
3498 let disk = new_test_file();
3499 let mut vmgs = Vmgs::format_new(disk.clone(), None).await.unwrap();
3500 let mut config = new_attestation_vm_config();
3501 config.tpm_persisted = false;
3502 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
3503 let tee = BootReportTee::new();
3504 let bios_guid = Guid::new_random();
3505 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
3506 let mut previous_dek = None;
3507
3508 for boot in 1..=2 {
3509 let result = initialize_platform_security(
3510 &get_pair.client,
3511 bios_guid,
3512 &config,
3513 &mut vmgs,
3514 Some(&tee),
3515 true,
3516 ldriver.clone(),
3517 GuestStateEncryptionPolicy::HardwareSealing,
3518 true,
3519 )
3520 .await
3521 .unwrap();
3522 assert!(result.runtime_tcb_floor.is_some());
3523 assert!(!result.host_attestation_settings.refresh_tpm_seeds);
3524 assert!(vmgs.encrypted());
3525 let active_dek = *vmgs.active_encryption_key().unwrap();
3526 assert_ne!(previous_dek, Some(active_dek));
3527 assert_eq!(&*tee.report_data.lock(), &vec![[0; REPORT_DATA_SIZE]; boot]);
3528
3529 drop(vmgs);
3532 vmgs = Vmgs::open(disk.clone(), None).await.unwrap();
3533 assert!(matches!(
3534 vmgs.active_encryption_key(),
3535 Err(::vmgs::Error::NeedsUnlock)
3536 ));
3537 let protector = vmgs::read_hardware_key_protector(&mut vmgs).await.unwrap();
3538 let keys = HardwareDerivedKeys::derive_key(
3539 tee.supports_get_derived_key().unwrap(),
3540 &config,
3541 protector.key_derivation_policy().unwrap(),
3542 )
3543 .unwrap();
3544 assert_eq!(protector.unseal_key(&keys).unwrap(), active_dek);
3545 previous_dek = Some(active_dek);
3546 }
3547 }
3548
3549 #[async_test]
3550 async fn init_sec_required_stateless_lm_before_first_derivation_seals_on_destination(
3551 driver: DefaultDriver,
3552 ) {
3553 let get_pair = new_test_get(driver, false, None).await;
3554 let mut config = new_attestation_vm_config();
3555 config.tpm_persisted = false;
3556 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
3557 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
3558
3559 for migrate_after_report in [false, true] {
3560 let disk = new_test_file();
3561 let mut vmgs = Vmgs::format_new(disk.clone(), None).await.unwrap();
3562 assert!(!vmgs.encrypted());
3563 assert!(hardware_key_protector_is_empty(&mut vmgs).await);
3564 let tee = FirstDerivationMigrationTee::new();
3565 assert_eq!(
3566 tee.source.inner.tcb_version,
3567 tee.destination.inner.tcb_version
3568 );
3569 let boot_tee: &dyn TeeCall = if migrate_after_report {
3570 &tee
3571 } else {
3572 &tee.destination
3574 };
3575 let result = initialize_platform_security(
3576 &get_pair.client,
3577 Guid::new_random(),
3578 &config,
3579 &mut vmgs,
3580 Some(boot_tee),
3581 true,
3582 ldriver.clone(),
3583 GuestStateEncryptionPolicy::HardwareSealing,
3584 true,
3585 )
3586 .await
3587 .unwrap();
3588 assert!(result.runtime_tcb_floor.is_some());
3589 assert!(!result.host_attestation_settings.refresh_tpm_seeds);
3590 assert!(vmgs.encrypted());
3591 let active_dek = *vmgs.active_encryption_key().unwrap();
3592 assert_eq!(*tee.source.derivation_calls.lock(), 0);
3593 assert_eq!(*tee.destination.derivation_calls.lock(), 1);
3594
3595 drop(vmgs);
3598 let mut reopened = Vmgs::open(disk, None).await.unwrap();
3599 assert!(reopened.encrypted());
3600 assert!(matches!(
3601 reopened.active_encryption_key(),
3602 Err(::vmgs::Error::NeedsUnlock)
3603 ));
3604 let protector = vmgs::read_hardware_key_protector(&mut reopened)
3605 .await
3606 .unwrap();
3607 let policy = KeyDerivationPolicy {
3608 svn: tee_call::KeyDerivationSvn::Snp {
3609 tcb_version: tee.source.inner.tcb_version,
3610 },
3611 mix_measurement: true,
3612 };
3613 let stored_policy = protector.key_derivation_policy().unwrap();
3614 assert!(stored_policy.mix_measurement);
3615 assert!(
3616 matches!(stored_policy.svn, tee_call::KeyDerivationSvn::Snp { tcb_version }
3617 if tcb_version == tee.source.inner.tcb_version)
3618 );
3619 if migrate_after_report {
3620 let policies = tee.derivation_policies.lock();
3621 assert_eq!(policies.len(), 1);
3622 assert!(policies[0].mix_measurement);
3623 assert!(
3624 matches!(policies[0].svn, tee_call::KeyDerivationSvn::Snp { tcb_version }
3625 if tcb_version == tee.source.inner.tcb_version)
3626 );
3627 } else {
3628 assert!(tee.derivation_policies.lock().is_empty());
3629 }
3630
3631 let source = tee.source.inner.supports_get_derived_key().unwrap();
3634 let destination = tee.destination.inner.supports_get_derived_key().unwrap();
3635 assert_ne!(
3636 source.get_derived_key(policy).unwrap(),
3637 destination.get_derived_key(policy).unwrap()
3638 );
3639 let source_keys = HardwareDerivedKeys::derive_key(source, &config, policy).unwrap();
3640 assert!(matches!(
3641 protector.unseal_key(&source_keys),
3642 Err(HardwareKeySealingError::HardwareKeyProtectorHmacVerificationFailed)
3643 ));
3644 let destination_keys =
3645 HardwareDerivedKeys::derive_key(destination, &config, policy).unwrap();
3646 let unsealed_dek = protector.unseal_key(&destination_keys).unwrap();
3647 assert_eq!(unsealed_dek, active_dek);
3648 reopened
3649 .unlock_with_encryption_key(&unsealed_dek)
3650 .await
3651 .unwrap();
3652 assert_eq!(reopened.active_encryption_key().unwrap(), &active_dek);
3653
3654 if migrate_after_report {
3657 assert_eq!(&*tee.source.report_data.lock(), &[[0; REPORT_DATA_SIZE]]);
3658 assert!(tee.destination.report_data.lock().is_empty());
3659 } else {
3660 assert!(tee.source.report_data.lock().is_empty());
3661 assert_eq!(
3662 &*tee.destination.report_data.lock(),
3663 &[[0; REPORT_DATA_SIZE]]
3664 );
3665 }
3666 }
3667 }
3668
3669 #[async_test]
3670 async fn init_sec_required_stateless_lm_rejects_source_svn_without_enrollment(
3671 driver: DefaultDriver,
3672 ) {
3673 let get_pair = new_test_get(driver, false, None).await;
3674 let disk = new_test_file();
3675 let mut vmgs = Vmgs::format_new(disk.clone(), None).await.unwrap();
3676 assert!(!vmgs.encrypted());
3677 assert!(hardware_key_protector_is_empty(&mut vmgs).await);
3678 let mut config = new_attestation_vm_config();
3679 config.tpm_persisted = false;
3680 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
3681 let mut tee = FirstDerivationMigrationTee::new();
3682 tee.source.inner.tcb_version += 1;
3685 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
3686 let result = initialize_platform_security(
3687 &get_pair.client,
3688 Guid::new_random(),
3689 &config,
3690 &mut vmgs,
3691 Some(&tee),
3692 true,
3693 ldriver,
3694 GuestStateEncryptionPolicy::HardwareSealing,
3695 true,
3696 )
3697 .await;
3698 assert!(matches!(
3701 result,
3702 Err(Error(AttestationErrorInner::GetDerivedKeys(
3703 GetDerivedKeysError::HardwareSealingRequiredButNotSupported
3704 )))
3705 ));
3706 {
3707 let policies = tee.derivation_policies.lock();
3708 assert_eq!(policies.len(), 1);
3709 assert!(policies[0].mix_measurement);
3710 assert!(
3711 matches!(policies[0].svn, tee_call::KeyDerivationSvn::Snp { tcb_version }
3712 if tcb_version == tee.source.inner.tcb_version)
3713 );
3714 }
3715 assert_eq!(&*tee.source.report_data.lock(), &[[0; REPORT_DATA_SIZE]]);
3716 assert!(tee.destination.report_data.lock().is_empty());
3717 assert_eq!(*tee.source.derivation_calls.lock(), 0);
3718 assert_eq!(*tee.destination.derivation_calls.lock(), 0);
3719 assert!(!vmgs.encrypted());
3720 assert!(vmgs.active_encryption_key().is_err());
3721 assert!(hardware_key_protector_is_empty(&mut vmgs).await);
3722 assert!(key_protector_is_empty(&mut vmgs).await);
3723 assert!(key_protector_by_id_is_empty(&mut vmgs).await);
3724
3725 drop(vmgs);
3726 let mut reopened = Vmgs::open(disk, None).await.unwrap();
3727 assert!(!reopened.encrypted());
3728 assert!(reopened.active_encryption_key().is_err());
3729 assert!(hardware_key_protector_is_empty(&mut reopened).await);
3730 assert!(key_protector_is_empty(&mut reopened).await);
3731 assert!(key_protector_by_id_is_empty(&mut reopened).await);
3732 }
3733
3734 #[async_test]
3735 async fn init_sec_required_stateless_derivation_failure_cannot_boot(driver: DefaultDriver) {
3736 let get_pair = new_test_get(driver, false, None).await;
3737 let mut config = new_attestation_vm_config();
3738 config.tpm_persisted = false;
3739 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
3740 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
3741
3742 for encrypted in [false, true] {
3743 let disk = new_test_file();
3744 let mut vmgs = Vmgs::format_new(disk.clone(), None).await.unwrap();
3745 let bios_guid = Guid::new_random();
3746 let mut tee = BootReportTee::new();
3747 if encrypted {
3748 let provisioned = initialize_platform_security(
3749 &get_pair.client,
3750 bios_guid,
3751 &config,
3752 &mut vmgs,
3753 Some(&tee),
3754 true,
3755 ldriver.clone(),
3756 GuestStateEncryptionPolicy::HardwareSealing,
3757 true,
3758 )
3759 .await
3760 .unwrap();
3761 assert!(provisioned.runtime_tcb_floor.is_some());
3762 drop(vmgs);
3763 vmgs = Vmgs::open(disk, None).await.unwrap();
3764 }
3765 tee.fail_derivation = true;
3766 tee.report_data.lock().clear();
3767 *tee.derivation_calls.lock() = 0;
3768 let result = initialize_platform_security(
3769 &get_pair.client,
3770 bios_guid,
3771 &config,
3772 &mut vmgs,
3773 Some(&tee),
3774 true,
3775 ldriver.clone(),
3776 GuestStateEncryptionPolicy::HardwareSealing,
3777 true,
3778 )
3779 .await;
3780 assert!(result.is_err());
3781 assert_eq!(&*tee.report_data.lock(), &[[0; REPORT_DATA_SIZE]]);
3782 assert!(*tee.derivation_calls.lock() > 0);
3783 assert_eq!(vmgs.encrypted(), encrypted);
3784 assert!(vmgs.active_encryption_key().is_err());
3785 }
3786 }
3787
3788 #[async_test]
3789 async fn init_sec_optional_sealing_requires_this_boot_write(driver: DefaultDriver) {
3790 let get_pair = new_test_get(driver, true, None).await;
3791 let mut config = new_attestation_vm_config();
3792 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
3793 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
3794
3795 for policy in [
3798 GuestStateEncryptionPolicy::Auto,
3799 GuestStateEncryptionPolicy::None,
3800 ] {
3801 let disk = new_test_file();
3802 let mut vmgs = Vmgs::format_new(disk.clone(), None).await.unwrap();
3803 let bios_guid = Guid::new_random();
3804 let mut tee = BootReportTee::new();
3805 let provisioned = initialize_platform_security(
3806 &get_pair.client,
3807 bios_guid,
3808 &config,
3809 &mut vmgs,
3810 Some(&tee),
3811 false,
3812 ldriver.clone(),
3813 policy,
3814 true,
3815 )
3816 .await
3817 .unwrap();
3818 assert!(provisioned.runtime_tcb_floor.is_some());
3819 let old_dek = *vmgs.active_encryption_key().unwrap();
3820 let old_protector = vmgs::read_hardware_key_protector(&mut vmgs).await.unwrap();
3821 drop(vmgs);
3822 vmgs = Vmgs::open(disk, None).await.unwrap();
3823
3824 tee.fail_derivation = true;
3828 *tee.derivation_calls.lock() = 0;
3829 let result = initialize_platform_security(
3830 &get_pair.client,
3831 bios_guid,
3832 &config,
3833 &mut vmgs,
3834 Some(&tee),
3835 false,
3836 ldriver.clone(),
3837 policy,
3838 true,
3839 )
3840 .await
3841 .unwrap();
3842 assert!(result.runtime_tcb_floor.is_none());
3843 assert!(*tee.derivation_calls.lock() > 0);
3844 assert_eq!(tee.report_data.lock().len(), 2);
3845 assert!(vmgs.encrypted());
3846 assert_ne!(vmgs.active_encryption_key().unwrap(), &old_dek);
3847 let protector = vmgs::read_hardware_key_protector(&mut vmgs).await.unwrap();
3848 tee.fail_derivation = false;
3850 let keys = HardwareDerivedKeys::derive_key(
3851 tee.supports_get_derived_key().unwrap(),
3852 &config,
3853 old_protector.key_derivation_policy().unwrap(),
3854 )
3855 .unwrap();
3856 assert_eq!(protector.unseal_key(&keys).unwrap(), old_dek);
3857 }
3858 }
3859
3860 #[async_test]
3861 async fn derived_gsp_tracks_writes_but_gsp_by_id_does_not(driver: DefaultDriver) {
3862 for use_gsp_by_id in [false, true] {
3863 for fail_derivation in [false, true] {
3864 let mut vmgs = new_formatted_vmgs().await;
3865 let mut config = new_attestation_vm_config();
3866 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
3867 let mut tee = BootReportTee::new();
3868 tee.fail_derivation = fail_derivation;
3869 let mut gsp = get_protocol::GuestStateProtectionResponse::new_zeroed();
3870 gsp.message_header = get_protocol::HeaderGeneric::new(
3871 get_protocol::HostRequests::GUEST_STATE_PROTECTION,
3872 );
3873 if !use_gsp_by_id {
3874 gsp.encrypted_gsp.length = 32;
3875 gsp.encrypted_gsp.buffer[..32].fill(0x55);
3876 }
3877 let mut responses = vec![TestGetResponses::new(Event::Response(
3878 gsp.as_bytes().to_vec(),
3879 ))];
3880 if use_gsp_by_id {
3881 let mut by_id = get_protocol::GuestStateProtectionByIdResponse::new_zeroed();
3882 by_id.message_header = get_protocol::HeaderGeneric::new(
3883 get_protocol::HostRequests::GUEST_STATE_PROTECTION_BY_ID,
3884 );
3885 by_id.seed.length = 32;
3886 by_id.seed.buffer[..32].fill(0x66);
3887 responses.push(TestGetResponses::new(Event::Response(
3888 by_id.as_bytes().to_vec(),
3889 )));
3890 }
3891 let get_pair = guest_emulation_transport::test_utilities::new_transport_pair(
3892 driver.clone(),
3893 Some(responses),
3894 get_protocol::ProtocolVersion::NICKEL_REV2,
3895 None,
3896 None,
3897 )
3898 .await;
3899 let mut kp = KeyProtector::new_zeroed();
3900 let mut kp_by_id = new_key_protector_by_id(Some(Guid::default()), None, false);
3901 let bios_guid = Guid::new_random();
3902 let derived = get_derived_keys(
3903 &get_pair.client,
3904 Some(&tee),
3905 &mut vmgs,
3906 &mut kp,
3907 &mut kp_by_id,
3908 bios_guid,
3909 &config,
3910 false,
3911 None,
3912 None,
3913 Some(KeyDerivationPolicy {
3914 svn: tee_call::KeyDerivationSvn::Snp {
3915 tcb_version: tee.inner.tcb_version,
3916 },
3917 mix_measurement: true,
3918 }),
3919 GuestStateEncryptionPolicy::Auto,
3920 true,
3921 false,
3922 false,
3923 )
3924 .await
3925 .unwrap();
3926 let eligible = !use_gsp_by_id && !fail_derivation;
3927 assert_eq!(derived.hardware_key_protector_written, eligible);
3928 assert!(derived.hardware_key_protector.is_none());
3929 assert_eq!(derived.key_protector_settings.use_gsp_by_id, use_gsp_by_id);
3930 let sealed_key = derived
3931 .derived_keys
3932 .as_ref()
3933 .filter(|_| derived.hardware_key_protector_written)
3934 .map(|keys| keys.encrypt_egress);
3935 unlock_vmgs_data_store(
3936 &mut vmgs,
3937 false,
3938 &mut kp,
3939 &mut kp_by_id,
3940 derived.hardware_key_protector,
3941 derived.derived_keys,
3942 derived.key_protector_settings,
3943 bios_guid,
3944 )
3945 .await
3946 .unwrap();
3947 assert!(vmgs.encrypted());
3948 assert_eq!(
3949 finalize_hardware_sealing(&mut vmgs, sealed_key, false)
3950 .await
3951 .unwrap(),
3952 eligible
3953 );
3954 }
3955 }
3956 }
3957
3958 #[async_test]
3959 async fn old_egress_unlock_does_not_enroll_different_sealed_key() {
3960 let mut vmgs = new_formatted_vmgs().await;
3961 let active_dek = [0x33; AES_GCM_KEY_LENGTH];
3962 let sealed_dek = [0x44; AES_GCM_KEY_LENGTH];
3963 vmgs.test_add_new_encryption_key(&active_dek, EncryptionAlgorithm::AES_GCM)
3964 .await
3965 .unwrap();
3966 let tee = BootReportTee::new();
3967 let mut config = new_attestation_vm_config();
3968 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
3969 let hardware_keys = HardwareDerivedKeys::derive_key(
3970 tee.supports_get_derived_key().unwrap(),
3971 &config,
3972 KeyDerivationPolicy {
3973 svn: tee_call::KeyDerivationSvn::Snp {
3974 tcb_version: tee.inner.tcb_version,
3975 },
3976 mix_measurement: true,
3977 },
3978 )
3979 .unwrap();
3980 let protector = hardware_key_sealing::seal_key(&hardware_keys, &sealed_dek).unwrap();
3981 let mut key_protector = KeyProtector::new_zeroed();
3982 let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
3983 unlock_vmgs_data_store(
3984 &mut vmgs,
3985 true,
3986 &mut key_protector,
3987 &mut key_protector_by_id,
3988 Some(protector),
3989 Some(Keys {
3990 ingress: sealed_dek,
3991 decrypt_egress: Some(active_dek),
3992 encrypt_egress: sealed_dek,
3993 }),
3994 KeyProtectorSettings {
3995 should_write_kp: false,
3996 use_gsp_by_id: false,
3997 use_hardware_unlock: false,
3998 decrypt_gsp_type: GspType::None,
3999 encrypt_gsp_type: GspType::None,
4000 },
4001 Guid::new_random(),
4002 )
4003 .await
4004 .unwrap();
4005 assert_eq!(vmgs.active_encryption_key().unwrap(), &active_dek);
4006 assert!(
4007 !finalize_hardware_sealing(&mut vmgs, Some(sealed_dek), false)
4008 .await
4009 .unwrap()
4010 );
4011 assert!(
4012 !finalize_hardware_sealing(&mut vmgs, None, false)
4013 .await
4014 .unwrap()
4015 );
4016 }
4017
4018 fn init_sec_with_retry_reports(
4019 report_svns: [u64; 2],
4020 ) -> (
4021 Option<runtime_sealing::RuntimeTcbFloor>,
4022 [u8; AES_GCM_KEY_LENGTH],
4023 ) {
4024 let (get_thread, driver) = pal_async::DefaultPool::spawn_on_thread("boot-report-retry-get");
4028 let result = pal_async::local::block_with_io(async |ldriver| {
4029 let mut plan = IgvmAgentTestPlan::default();
4030 plan.insert(
4031 IgvmAttestRequestType::KEY_RELEASE_REQUEST,
4032 VecDeque::from([
4033 IgvmAgentAction::RespondSuccess,
4034 IgvmAgentAction::NoResponse,
4038 IgvmAgentAction::RespondSuccess,
4039 ]),
4040 );
4041 let get_pair = new_test_get(driver, true, Some(plan)).await;
4042 let bios_guid = Guid::new_random();
4043 let mut config = new_attestation_vm_config();
4044 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
4045 let disk = new_test_file();
4046 let mut vmgs = Vmgs::format_new(disk.clone(), None).await.unwrap();
4047 let provision_tee = BootReportTee::new();
4048
4049 let provisioned = initialize_platform_security(
4052 &get_pair.client,
4053 bios_guid,
4054 &config,
4055 &mut vmgs,
4056 Some(&provision_tee),
4057 false,
4058 ldriver.clone(),
4059 GuestStateEncryptionPolicy::Auto,
4060 true,
4061 )
4062 .await
4063 .unwrap();
4064 assert!(provisioned.runtime_tcb_floor.is_some());
4065 assert_eq!(provision_tee.report_data.lock().len(), 1);
4066 assert!(vmgs.encrypted());
4067 assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
4068
4069 vmgs.delete_file(FileId::HW_KEY_PROTECTOR).await.unwrap();
4073 vmgs.flush().await.unwrap();
4074 drop(vmgs);
4075 let mut vmgs = Vmgs::open(disk, None).await.unwrap();
4076 assert!(vmgs.encrypted());
4077 assert!(matches!(
4078 vmgs.active_encryption_key(),
4079 Err(::vmgs::Error::NeedsUnlock)
4080 ));
4081 assert!(hardware_key_protector_is_empty(&mut vmgs).await);
4082
4083 let tee = SequencedBootReportTee {
4084 inner: BootReportTee::new(),
4085 report_svns: parking_lot::Mutex::new(report_svns.into()),
4086 };
4087 let recovered = initialize_platform_security(
4088 &get_pair.client,
4089 bios_guid,
4090 &config,
4091 &mut vmgs,
4092 Some(&tee),
4093 false,
4094 ldriver,
4095 GuestStateEncryptionPolicy::Auto,
4096 true,
4097 )
4098 .await
4099 .unwrap();
4100
4101 assert!(tee.report_svns.lock().is_empty());
4104 {
4105 let reports = tee.inner.report_data.lock();
4106 assert_eq!(reports.len(), 2);
4107 assert!(reports.iter().all(|data| *data != [0; REPORT_DATA_SIZE]));
4108 }
4109 assert_eq!(provision_tee.report_data.lock().len(), 1);
4110 assert!(vmgs.encrypted());
4111 let active_dek = *vmgs.active_encryption_key().unwrap();
4112
4113 let protector = vmgs::read_hardware_key_protector(&mut vmgs).await.unwrap();
4117 let policy = protector.key_derivation_policy().unwrap();
4118 assert!(policy.mix_measurement);
4119 assert!(matches!(
4120 policy.svn,
4121 tee_call::KeyDerivationSvn::Snp { tcb_version } if tcb_version == report_svns[1]
4122 ));
4123 let keys = HardwareDerivedKeys::derive_key(
4124 tee.supports_get_derived_key().unwrap(),
4125 &config,
4126 policy,
4127 )
4128 .unwrap();
4129 assert_eq!(protector.unseal_key(&keys).unwrap(), active_dek);
4130 vmgs.unlock_with_encryption_key(&active_dek).await.unwrap();
4131
4132 (recovered.runtime_tcb_floor, active_dek)
4133 });
4134 get_thread.join().unwrap();
4135 result
4136 }
4137
4138 #[test]
4139 fn init_sec_retry_high_then_lower_svn_succeeds_without_runtime_floor() {
4140 let (floor, _) = init_sec_with_retry_reports([0x1235, 0x1234]);
4141 assert!(floor.is_none());
4144 }
4145
4146 #[test]
4147 fn init_sec_retry_low_then_higher_svn_exports_highest_runtime_floor() {
4148 let (floor, active_dek) = init_sec_with_retry_reports([0x1234, 0x1235]);
4149 let mut floor = floor.unwrap();
4150 let mut config = new_attestation_vm_config();
4151 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
4152
4153 let mut tee = BootReportTee::new();
4156 let err = floor
4157 .create_protector(&tee, &config, &active_dek)
4158 .unwrap_err();
4159 assert_eq!(
4160 err.to_string(),
4161 "local TCB has a component below the runtime floor"
4162 );
4163 tee.inner.tcb_version = 0x1235;
4164 let protector = floor.create_protector(&tee, &config, &active_dek).unwrap();
4165 assert!(
4166 runtime_sealing::protector_matches(&tee, &config, &protector, &active_dek).unwrap()
4167 );
4168 assert_eq!(&*tee.report_data.lock(), &[[0; REPORT_DATA_SIZE]; 2]);
4169 }
4170
4171 #[async_test]
4172 async fn init_sec_hardware_cached_lower_svn_preserves_boot_policy(driver: DefaultDriver) {
4173 let get_pair = new_test_get(driver, false, None).await;
4174 for malformed in [false, true] {
4175 let mut vmgs = new_formatted_vmgs().await;
4176 let bootstrap = [0x33; AES_GCM_KEY_LENGTH];
4177 vmgs.test_add_new_encryption_key(&bootstrap, EncryptionAlgorithm::AES_GCM)
4178 .await
4179 .unwrap();
4180 let mut tee = BootReportTee::new();
4181 let mut config = new_attestation_vm_config();
4182 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
4183 let cached_svn = tee.inner.tcb_version;
4184 let keys = HardwareDerivedKeys::derive_key(
4185 tee.supports_get_derived_key().unwrap(),
4186 &config,
4187 KeyDerivationPolicy {
4188 svn: tee_call::KeyDerivationSvn::Snp {
4189 tcb_version: cached_svn,
4190 },
4191 mix_measurement: true,
4192 },
4193 )
4194 .unwrap();
4195 let protector = hardware_key_sealing::seal_key(&keys, &bootstrap).unwrap();
4196 vmgs::write_hardware_key_protector(&protector, &mut vmgs)
4197 .await
4198 .unwrap();
4199
4200 tee.inner.tcb_version += 1;
4203 tee.malformed = malformed;
4204 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4205 let result = initialize_platform_security(
4206 &get_pair.client,
4207 Guid::new_random(),
4208 &config,
4209 &mut vmgs,
4210 Some(&tee),
4211 true,
4212 ldriver,
4213 GuestStateEncryptionPolicy::HardwareSealing,
4214 true,
4215 )
4216 .await
4217 .unwrap();
4218 assert!(vmgs.encrypted());
4219 assert!(!result.host_attestation_settings.refresh_tpm_seeds);
4220 assert_eq!(&*tee.report_data.lock(), &[[0; REPORT_DATA_SIZE]]);
4222 let rotated = vmgs::read_hardware_key_protector(&mut vmgs).await.unwrap();
4223 assert!(matches!(
4224 rotated.key_derivation_policy().unwrap().svn,
4225 tee_call::KeyDerivationSvn::Snp { tcb_version } if tcb_version == cached_svn
4226 ));
4227 let active_dek = rotated.unseal_key(&keys).unwrap();
4228 vmgs.unlock_with_encryption_key(&active_dek).await.unwrap();
4229
4230 if malformed {
4231 assert!(result.runtime_tcb_floor.is_none());
4233 } else {
4234 let mut floor = result.runtime_tcb_floor.unwrap();
4235 tee.inner.tcb_version = cached_svn;
4236 let err = floor
4237 .create_protector(&tee, &config, &active_dek)
4238 .unwrap_err();
4239 assert_eq!(
4240 err.to_string(),
4241 "local TCB has a component below the runtime floor"
4242 );
4243 }
4244 }
4245 }
4246
4247 #[async_test]
4248 async fn init_sec_skr_failure_hardware_fallback_exports_existing_report(driver: DefaultDriver) {
4249 let mut vmgs = new_formatted_vmgs().await;
4250 let mut plan = IgvmAgentTestPlan::default();
4251 plan.insert(
4252 IgvmAttestRequestType::WRAPPED_KEY_REQUEST,
4253 VecDeque::from([
4254 IgvmAgentAction::RespondSuccess,
4255 IgvmAgentAction::RespondFailure,
4256 ]),
4257 );
4258 let get_pair = new_test_get(driver, true, Some(plan)).await;
4259 let bios_guid = Guid::new_random();
4260 let mut config = new_attestation_vm_config();
4261 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
4262 let mut tee = BootReportTee::new();
4263 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4264 let first = initialize_platform_security(
4265 &get_pair.client,
4266 bios_guid,
4267 &config,
4268 &mut vmgs,
4269 Some(&tee),
4270 false,
4271 ldriver.clone(),
4272 GuestStateEncryptionPolicy::Auto,
4273 true,
4274 )
4275 .await
4276 .unwrap();
4277 assert!(first.runtime_tcb_floor.is_some());
4278 assert_eq!(tee.report_data.lock().len(), 1);
4279 assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
4280
4281 let cached_svn = tee.inner.tcb_version;
4284 tee.inner.tcb_version += 1;
4285 let recovered = initialize_platform_security(
4286 &get_pair.client,
4287 bios_guid,
4288 &config,
4289 &mut vmgs,
4290 Some(&tee),
4291 false,
4292 ldriver,
4293 GuestStateEncryptionPolicy::Auto,
4294 true,
4295 )
4296 .await
4297 .unwrap();
4298 assert!(vmgs.encrypted());
4299 {
4300 let reports = tee.report_data.lock();
4301 assert_eq!(reports.len(), 2);
4302 assert!(reports.iter().all(|data| *data != [0; REPORT_DATA_SIZE]));
4304 }
4305 let mut floor = recovered.runtime_tcb_floor.unwrap();
4306 tee.inner.tcb_version = cached_svn;
4307 let err = floor.create_protector(&tee, &config, &[0; 32]).unwrap_err();
4308 assert_eq!(
4309 err.to_string(),
4310 "local TCB has a component below the runtime floor"
4311 );
4312 }
4313
4314 #[async_test]
4315 async fn init_sec_suppressed_eligible_tee_does_not_bootstrap_floor(driver: DefaultDriver) {
4316 let mut vmgs = new_formatted_vmgs().await;
4317 let get_pair = new_test_get(driver, false, None).await;
4318 let tee = BootReportTee::new();
4319 let mut config = new_attestation_vm_config();
4320 config.hardware_sealing_policy = HardwareSealingPolicy::Hash;
4321 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4322 let result = initialize_platform_security(
4323 &get_pair.client,
4324 Guid::new_random(),
4325 &config,
4326 &mut vmgs,
4327 Some(&tee),
4328 true,
4329 ldriver,
4330 GuestStateEncryptionPolicy::None,
4331 true,
4332 )
4333 .await
4334 .unwrap();
4335 assert!(result.runtime_tcb_floor.is_none());
4336 assert!(tee.report_data.lock().is_empty());
4337 assert_eq!(*tee.derivation_calls.lock(), 0);
4338 assert!(!vmgs.encrypted());
4339 }
4340
4341 #[async_test]
4342 async fn init_sec_suppress_attestation(driver: DefaultDriver) {
4343 let mut vmgs = new_formatted_vmgs().await;
4344
4345 let agent = SecurityProfile {
4347 agent_data: [0xAA; AGENT_DATA_MAX_SIZE],
4348 };
4349 vmgs.write_file(FileId::ATTEST, agent.as_bytes())
4350 .await
4351 .unwrap();
4352
4353 let get_pair = new_test_get(driver, false, None).await;
4355
4356 let bios_guid = Guid::new_random();
4357 let att_cfg = test_attestation_config();
4358
4359 assert!(!vmgs.encrypted());
4361
4362 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4364 let res = initialize_platform_security(
4365 &get_pair.client,
4366 bios_guid,
4367 &att_cfg,
4368 &mut vmgs,
4369 None, true, ldriver,
4372 GuestStateEncryptionPolicy::None,
4373 true,
4374 )
4375 .await
4376 .unwrap();
4377
4378 assert!(!vmgs.encrypted());
4380 assert!(key_protector_is_empty(&mut vmgs).await);
4381 assert!(hardware_key_protector_is_empty(&mut vmgs).await);
4382 assert_eq!(res.agent_data.unwrap(), agent.agent_data.to_vec());
4384 assert!(res.guest_secret_key.is_none());
4386 }
4387
4388 #[async_test]
4389 async fn init_sec_secure_key_release_with_wrapped_key_request(driver: DefaultDriver) {
4390 let mut vmgs = new_formatted_vmgs().await;
4391
4392 let get_pair = new_test_get(driver, true, None).await;
4394
4395 let bios_guid = Guid::new_random();
4396 let att_cfg = new_attestation_vm_config();
4397 let tee = MockTeeCall::new([0x12u8; 32]);
4398
4399 assert!(!vmgs.encrypted());
4401
4402 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4404 let res = initialize_platform_security(
4405 &get_pair.client,
4406 bios_guid,
4407 &att_cfg,
4408 &mut vmgs,
4409 Some(&tee),
4410 false,
4411 ldriver.clone(),
4412 GuestStateEncryptionPolicy::Auto,
4413 true,
4414 )
4415 .await
4416 .unwrap();
4417
4418 assert!(vmgs.encrypted());
4420 assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
4421
4422 let key_reference = serde_json::json!({
4425 "key_info": {
4426 "host": "name"
4427 },
4428 "attestation_info": {
4429 "host": "attestation_name"
4430 }
4431 });
4432 let key_reference = serde_json::to_string(&key_reference).unwrap();
4433 let key_reference = key_reference.as_bytes();
4434 let mut expected_agent_data = [0u8; AGENT_DATA_MAX_SIZE];
4435 expected_agent_data[..key_reference.len()].copy_from_slice(key_reference);
4436 assert_eq!(res.agent_data.unwrap(), expected_agent_data.to_vec());
4437 assert!(res.guest_secret_key.is_none());
4439
4440 initialize_platform_security(
4442 &get_pair.client,
4443 bios_guid,
4444 &att_cfg,
4445 &mut vmgs,
4446 Some(&tee),
4447 false,
4448 ldriver,
4449 GuestStateEncryptionPolicy::Auto,
4450 true,
4451 )
4452 .await
4453 .unwrap();
4454
4455 assert!(vmgs.encrypted());
4457 }
4458
4459 #[async_test]
4460 async fn init_sec_secure_key_release_without_wrapped_key_request(driver: DefaultDriver) {
4461 let mut vmgs = new_formatted_vmgs().await;
4462
4463 let agent = SecurityProfile {
4465 agent_data: [0xAA; AGENT_DATA_MAX_SIZE],
4466 };
4467 vmgs.write_file(FileId::ATTEST, agent.as_bytes())
4468 .await
4469 .unwrap();
4470
4471 let mut plan = IgvmAgentTestPlan::default();
4473 plan.insert(
4474 IgvmAttestRequestType::WRAPPED_KEY_REQUEST,
4475 VecDeque::from([IgvmAgentAction::NoResponse, IgvmAgentAction::NoResponse]),
4476 );
4477
4478 let get_pair = new_test_get(driver, true, Some(plan)).await;
4480
4481 let bios_guid = Guid::new_random();
4482 let att_cfg = new_attestation_vm_config();
4483 let tee = MockTeeCall::new([0x12u8; 32]);
4484
4485 assert!(!vmgs.encrypted());
4487
4488 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4490 let res = initialize_platform_security(
4491 &get_pair.client,
4492 bios_guid,
4493 &att_cfg,
4494 &mut vmgs,
4495 Some(&tee),
4496 false,
4497 ldriver.clone(),
4498 GuestStateEncryptionPolicy::Auto,
4499 true,
4500 )
4501 .await
4502 .unwrap();
4503
4504 assert!(vmgs.encrypted());
4506 assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
4507 assert_eq!(res.agent_data.clone().unwrap(), agent.agent_data.to_vec());
4509 assert!(res.guest_secret_key.is_none());
4511
4512 let res = initialize_platform_security(
4514 &get_pair.client,
4515 bios_guid,
4516 &att_cfg,
4517 &mut vmgs,
4518 Some(&tee),
4519 false,
4520 ldriver,
4521 GuestStateEncryptionPolicy::Auto,
4522 true,
4523 )
4524 .await
4525 .unwrap();
4526
4527 assert!(vmgs.encrypted());
4529 assert_eq!(res.agent_data.clone().unwrap(), agent.agent_data.to_vec());
4531 assert!(res.guest_secret_key.is_none());
4533 }
4534
4535 #[async_test]
4536 async fn init_sec_secure_key_release_hw_sealing_backup(driver: DefaultDriver) {
4537 let mut vmgs = new_formatted_vmgs().await;
4538
4539 let mut plan = IgvmAgentTestPlan::default();
4541 plan.insert(
4542 IgvmAttestRequestType::WRAPPED_KEY_REQUEST,
4543 VecDeque::from([
4544 IgvmAgentAction::RespondSuccess,
4545 IgvmAgentAction::RespondFailure,
4547 IgvmAgentAction::RespondFailure,
4548 IgvmAgentAction::RespondFailure,
4549 IgvmAgentAction::RespondFailure,
4550 IgvmAgentAction::RespondFailure,
4551 IgvmAgentAction::RespondFailure,
4552 IgvmAgentAction::RespondFailure,
4553 IgvmAgentAction::RespondFailure,
4554 IgvmAgentAction::RespondFailure,
4555 IgvmAgentAction::RespondFailure,
4556 ]),
4557 );
4558
4559 let get_pair = new_test_get(driver, true, Some(plan)).await;
4560
4561 let bios_guid = Guid::new_random();
4562 let att_cfg = test_attestation_config();
4563
4564 assert!(!vmgs.encrypted());
4566
4567 let tee = MockTeeCall::new([0x12u8; 32]);
4569 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4570 let res = initialize_platform_security(
4571 &get_pair.client,
4572 bios_guid,
4573 &att_cfg,
4574 &mut vmgs,
4575 Some(&tee),
4576 false,
4577 ldriver.clone(),
4578 GuestStateEncryptionPolicy::Auto,
4579 true,
4580 )
4581 .await
4582 .unwrap();
4583
4584 assert!(vmgs.encrypted());
4586 assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
4587 let key_reference = serde_json::json!({
4590 "key_info": {
4591 "host": "name"
4592 },
4593 "attestation_info": {
4594 "host": "attestation_name"
4595 }
4596 });
4597 let key_reference = serde_json::to_string(&key_reference).unwrap();
4598 let key_reference = key_reference.as_bytes();
4599 let mut expected_agent_data = [0u8; AGENT_DATA_MAX_SIZE];
4600 expected_agent_data[..key_reference.len()].copy_from_slice(key_reference);
4601 assert_eq!(res.agent_data.unwrap(), expected_agent_data.to_vec());
4602 assert!(res.guest_secret_key.is_none());
4604
4605 initialize_platform_security(
4611 &get_pair.client,
4612 bios_guid,
4613 &att_cfg,
4614 &mut vmgs,
4615 Some(&tee),
4616 false,
4617 ldriver,
4618 GuestStateEncryptionPolicy::Auto,
4619 true,
4620 )
4621 .await
4622 .unwrap();
4623
4624 assert!(vmgs.encrypted());
4626 }
4627
4628 #[async_test]
4629 async fn init_sec_secure_key_release_skip_hw_unsealing(driver: DefaultDriver) {
4630 let mut vmgs = new_formatted_vmgs().await;
4631
4632 let mut plan = IgvmAgentTestPlan::default();
4636 plan.insert(
4637 IgvmAttestRequestType::KEY_RELEASE_REQUEST,
4638 VecDeque::from([
4639 IgvmAgentAction::RespondSuccess,
4640 IgvmAgentAction::RespondFailureSkipHwUnsealing,
4641 ]),
4642 );
4643
4644 let get_pair = new_test_get(driver, true, Some(plan)).await;
4645
4646 let bios_guid = Guid::new_random();
4647 let att_cfg = test_attestation_config();
4648
4649 assert!(!vmgs.encrypted());
4651
4652 let tee = MockTeeCall::new([0x12u8; 32]);
4654 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4655 let res = initialize_platform_security(
4656 &get_pair.client,
4657 bios_guid,
4658 &att_cfg,
4659 &mut vmgs,
4660 Some(&tee),
4661 false,
4662 ldriver.clone(),
4663 GuestStateEncryptionPolicy::Auto,
4664 true,
4665 )
4666 .await
4667 .unwrap();
4668
4669 assert!(vmgs.encrypted());
4671 assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
4672 let key_reference = serde_json::json!({
4674 "key_info": {
4675 "host": "name"
4676 },
4677 "attestation_info": {
4678 "host": "attestation_name"
4679 }
4680 });
4681 let key_reference = serde_json::to_string(&key_reference).unwrap();
4682 let key_reference = key_reference.as_bytes();
4683 let mut expected_agent_data = [0u8; AGENT_DATA_MAX_SIZE];
4684 expected_agent_data[..key_reference.len()].copy_from_slice(key_reference);
4685 assert_eq!(res.agent_data.unwrap(), expected_agent_data.to_vec());
4686 assert!(res.guest_secret_key.is_none());
4688
4689 let result = initialize_platform_security(
4697 &get_pair.client,
4698 bios_guid,
4699 &att_cfg,
4700 &mut vmgs,
4701 Some(&tee),
4702 false,
4703 ldriver,
4704 GuestStateEncryptionPolicy::Auto,
4705 true,
4706 )
4707 .await;
4708
4709 assert!(result.is_err());
4710 }
4711
4712 #[async_test]
4713 async fn init_sec_secure_key_release_no_hw_sealing_backup(driver: DefaultDriver) {
4714 let mut vmgs = new_formatted_vmgs().await;
4715
4716 let mut plan = IgvmAgentTestPlan::default();
4718 plan.insert(
4719 IgvmAttestRequestType::WRAPPED_KEY_REQUEST,
4720 VecDeque::from([
4721 IgvmAgentAction::RespondSuccess,
4722 IgvmAgentAction::RespondFailure,
4724 IgvmAgentAction::RespondFailure,
4725 IgvmAgentAction::RespondFailure,
4726 IgvmAgentAction::RespondFailure,
4727 IgvmAgentAction::RespondFailure,
4728 IgvmAgentAction::RespondFailure,
4729 IgvmAgentAction::RespondFailure,
4730 IgvmAgentAction::RespondFailure,
4731 IgvmAgentAction::RespondFailure,
4732 IgvmAgentAction::RespondFailure,
4733 ]),
4734 );
4735
4736 let get_pair = new_test_get(driver, true, Some(plan)).await;
4737
4738 let bios_guid = Guid::new_random();
4739 let att_cfg = test_attestation_config();
4740 let tee = MockTeeCallNoGetDerivedKey {};
4742
4743 assert!(!vmgs.encrypted());
4745
4746 let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
4748 let res = initialize_platform_security(
4749 &get_pair.client,
4750 bios_guid,
4751 &att_cfg,
4752 &mut vmgs,
4753 Some(&tee),
4754 false,
4755 ldriver.clone(),
4756 GuestStateEncryptionPolicy::Auto,
4757 true,
4758 )
4759 .await
4760 .unwrap();
4761
4762 assert!(vmgs.encrypted());
4764 assert!(hardware_key_protector_is_empty(&mut vmgs).await);
4765 let key_reference = serde_json::json!({
4768 "key_info": {
4769 "host": "name"
4770 },
4771 "attestation_info": {
4772 "host": "attestation_name"
4773 }
4774 });
4775 let key_reference = serde_json::to_string(&key_reference).unwrap();
4776 let key_reference = key_reference.as_bytes();
4777 let mut expected_agent_data = [0u8; AGENT_DATA_MAX_SIZE];
4778 expected_agent_data[..key_reference.len()].copy_from_slice(key_reference);
4779 assert_eq!(res.agent_data.unwrap(), expected_agent_data.to_vec());
4780 assert!(res.guest_secret_key.is_none());
4782
4783 let result = initialize_platform_security(
4785 &get_pair.client,
4786 bios_guid,
4787 &att_cfg,
4788 &mut vmgs,
4789 Some(&tee),
4790 false,
4791 ldriver,
4792 GuestStateEncryptionPolicy::Auto,
4793 true,
4794 )
4795 .await;
4796
4797 assert!(result.is_err());
4798 }
4799
4800 #[test]
4801 fn test_get_provenance_claims() {
4802 const PROVENANCE_DOC: &str = include_str!("../test_data/valid_jwt");
4804 let doc = PROVENANCE_DOC.trim().strip_prefix("placeholder_").unwrap();
4805 let claims = get_provenance_claims(doc.as_bytes()).unwrap();
4806 assert_eq!(
4807 claims.id,
4808 guid::guid!("03020100-0504-0706-0809-0a0b0c0d0e0f")
4809 );
4810 assert_eq!(
4811 claims.signer,
4812 "did:x509:0:sha256:EA76599D86897382AA519FF2BC0FA6B9C15D60DA2EBE53E72139CD317B0797ED:subject:fican.cvmprovisioningservice.core.azure-test.net"
4813 );
4814 }
4815
4816 #[test]
4817 fn test_derive_vmgsid() {
4818 const SEED_DOC_1: &str = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F,4C6162656C5F435053,436F6E746578745F564D4753,32";
4819 const SEED_DOC_2: &str = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F,4C6162656C5F435053,436F6E746578745F564D4753";
4820 const SEED_DOC_3: &str = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F,4C6162656C5F435053,436F6E746578745F564D4753,32,ABCDEF";
4821 const GUID: Guid = guid::guid!("b0587f2d-11e6-9f66-1af4-8b4a619147c8");
4822
4823 let vmgsid1 = derive_vmgsid(SEED_DOC_1.as_bytes()).unwrap();
4824 assert_eq!(vmgsid1, GUID);
4825
4826 let vmgsid2 = derive_vmgsid(SEED_DOC_2.as_bytes()).unwrap();
4827 assert_eq!(vmgsid2, GUID);
4828
4829 let vmgsid3 = derive_vmgsid(SEED_DOC_3.as_bytes()).unwrap();
4830 assert_eq!(vmgsid3, GUID);
4831 }
4832}