Skip to main content

underhill_attestation/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! This modules implements attestation protocols for Underhill to support TVM
5//! and CVM, including getting a tenant key via secure key release (SKR) for
6//! unlocking VMGS and requesting an attestation key (AK) certificate for TPM.
7//! The module also implements the VMGS unlocking process based on SKR.
8
9#![cfg(target_os = "linux")]
10#![forbid(unsafe_code)]
11
12mod hardware_key_sealing;
13mod igvm_attest;
14mod jwt;
15mod key_protector;
16mod secure_key_release;
17mod vmgs;
18
19#[cfg(test)]
20mod test_helpers;
21
22pub use igvm_attest::Error as IgvmAttestError;
23pub use igvm_attest::IgvmAttestRequestHelper;
24pub use igvm_attest::ak_cert::parse_response as parse_ak_cert_response;
25
26use crate::jwt::JwtError;
27use crate::jwt::JwtHelper;
28use ::vmgs::EncryptionAlgorithm;
29use ::vmgs::GspType;
30use ::vmgs::Vmgs;
31use crypto::rsa::RsaKeyPair;
32use crypto::sha_256::sha_256;
33use cvm_tracing::CVM_ALLOWED;
34use get_protocol::dps_json::GuestStateEncryptionPolicy;
35use guest_emulation_transport::GuestEmulationTransportClient;
36use guest_emulation_transport::api::GspExtendedStatusFlags;
37use guest_emulation_transport::api::GuestStateProtection;
38use guest_emulation_transport::api::GuestStateProtectionById;
39use guid::Guid;
40use hardware_key_sealing::HardwareDerivedKeys;
41use hardware_key_sealing::HardwareKeyProtectorExt as _;
42use key_protector::GetKeysFromKeyProtectorError;
43use key_protector::KeyProtectorExt as _;
44use mesh::MeshPayload;
45use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::AttestationVmConfig;
46use openhcl_attestation_protocol::igvm_attest::get::runtime_claims::VmgsProvisioner;
47use openhcl_attestation_protocol::vmgs::AES_GCM_KEY_LENGTH;
48use openhcl_attestation_protocol::vmgs::AGENT_DATA_MAX_SIZE;
49use openhcl_attestation_protocol::vmgs::HardwareKeyProtector;
50use openhcl_attestation_protocol::vmgs::KeyProtector;
51use openhcl_attestation_protocol::vmgs::SecurityProfile;
52use pal_async::local::LocalDriver;
53use secure_key_release::VmgsEncryptionKeys;
54use serde::Deserialize;
55use serde::Serialize;
56use static_assertions::const_assert_eq;
57use std::fmt::Debug;
58use tee_call::TeeCall;
59use thiserror::Error;
60use zerocopy::FromZeros;
61use zerocopy::IntoBytes;
62
63/// An attestation error.
64#[derive(Debug, Error)]
65#[error(transparent)]
66pub struct Error(AttestationErrorInner);
67
68impl<T: Into<AttestationErrorInner>> From<T> for Error {
69    fn from(value: T) -> Self {
70        Self(value.into())
71    }
72}
73
74#[derive(Debug, Error)]
75enum AttestationErrorInner {
76    #[error("read security profile from vmgs")]
77    ReadSecurityProfile(#[source] vmgs::ReadFromVmgsError),
78    #[error("failed to get derived keys")]
79    GetDerivedKeys(#[source] GetDerivedKeysError),
80    #[error("failed to read key protector from vmgs")]
81    ReadKeyProtector(#[source] vmgs::ReadFromVmgsError),
82    #[error("failed to read key protector by id from vmgs")]
83    ReadKeyProtectorById(#[source] vmgs::ReadFromVmgsError),
84    #[error("failed to unlock vmgs data store")]
85    UnlockVmgsDataStore(#[source] UnlockVmgsDataStoreError),
86    #[error("failed to read guest secret key from vmgs")]
87    ReadGuestSecretKey(#[source] vmgs::ReadFromVmgsError),
88    #[error("failed to verify VMGS provenance")]
89    Provenance(#[source] ProvenanceError),
90}
91
92#[derive(Debug, Error)]
93enum GetDerivedKeysError {
94    #[error("failed to get ingress/egress keys from the the key protector")]
95    GetKeysFromKeyProtector(#[source] GetKeysFromKeyProtectorError),
96    #[error("failed to fetch GSP")]
97    FetchGuestStateProtectionById(
98        #[source] guest_emulation_transport::error::GuestStateProtectionByIdError,
99    ),
100    #[error("GSP By Id required, but no GSP By Id found")]
101    GspByIdRequiredButNotFound,
102    #[error("failed to unseal the ingress key using hardware derived keys")]
103    UnsealIngressKeyUsingHardwareDerivedKeys(
104        #[source] hardware_key_sealing::HardwareKeySealingError,
105    ),
106    #[error("failed to get an ingress key from key protector")]
107    GetIngressKeyFromKpFailed,
108    #[error("failed to get an ingress key from guest state protection")]
109    GetIngressKeyFromKGspFailed,
110    #[error("failed to get an ingress key from guest state protection by id")]
111    GetIngressKeyFromKGspByIdFailed,
112    #[error("Encryption cannot be disabled if VMGS was previously encrypted")]
113    DisableVmgsEncryptionFailed,
114    #[error("VMGS encryption is required, but no encryption sources were found")]
115    EncryptionRequiredButNotFound,
116    #[error("failed to seal the egress key using hardware derived keys")]
117    SealEgressKeyUsingHardwareDerivedKeys(#[source] hardware_key_sealing::HardwareKeySealingError),
118    #[error("failed to write to `FileId::HW_KEY_PROTECTOR` in vmgs")]
119    VmgsWriteHardwareKeyProtector(#[source] vmgs::WriteToVmgsError),
120    #[error("failed to get derived key by id")]
121    GetDerivedKeyById(#[source] GetDerivedKeysByIdError),
122    #[error("failed to derive an ingress key")]
123    DeriveIngressKey(#[source] crypto::kbkdf::KbkdfError),
124    #[error("failed to derive an egress key")]
125    DeriveEgressKey(#[source] crypto::kbkdf::KbkdfError),
126}
127
128#[derive(Debug, Error)]
129enum GetDerivedKeysByIdError {
130    #[error("failed to derive an egress key based on current vm bios guid")]
131    DeriveEgressKeyUsingCurrentVmId(#[source] crypto::kbkdf::KbkdfError),
132    #[error("invalid derived egress key size {key_size}, expected {expected_size}")]
133    InvalidDerivedEgressKeySize {
134        key_size: usize,
135        expected_size: usize,
136    },
137    #[error("failed to derive an ingress key based on key protector Id from vmgs")]
138    DeriveIngressKeyUsingKeyProtectorId(#[source] crypto::kbkdf::KbkdfError),
139    #[error("invalid derived egress key size {key_size}, expected {expected_size}")]
140    InvalidDerivedIngressKeySize {
141        key_size: usize,
142        expected_size: usize,
143    },
144}
145
146#[derive(Debug, Error)]
147enum UnlockVmgsDataStoreError {
148    #[error("failed to unlock vmgs with the existing egress key")]
149    VmgsUnlockUsingExistingEgressKey(#[source] ::vmgs::Error),
150    #[error("failed to unlock vmgs with the existing ingress key")]
151    VmgsUnlockUsingExistingIngressKey(#[source] ::vmgs::Error),
152    #[error("failed to write key protector to vmgs")]
153    WriteKeyProtector(#[source] vmgs::WriteToVmgsError),
154    #[error("failed to read key protector by id to vmgs")]
155    WriteKeyProtectorById(#[source] vmgs::WriteToVmgsError),
156    #[error("failed to update the vmgs encryption key")]
157    UpdateVmgsEncryptionKey(#[source] ::vmgs::Error),
158    #[error("failed to persist all key protectors")]
159    PersistAllKeyProtectors(#[source] PersistAllKeyProtectorsError),
160}
161
162#[derive(Debug, Error)]
163enum PersistAllKeyProtectorsError {
164    #[error("failed to write key protector to vmgs")]
165    WriteKeyProtector(#[source] vmgs::WriteToVmgsError),
166    #[error("failed to read key protector by id to vmgs")]
167    WriteKeyProtectorById(#[source] vmgs::WriteToVmgsError),
168}
169
170#[derive(Debug, Error)]
171enum ProvenanceError {
172    #[error("failed to decode provenance doc")]
173    DecodeProvenanceDoc(#[source] JwtError),
174    #[error("failed to verify JWT signature")]
175    VerifySignature(#[source] JwtError),
176    #[error("invalid signature")]
177    InvalidSignature,
178    #[error("missing leaf certificate subject common name")]
179    MissingLeafCertSubjectName,
180    #[error("invalid root certificate")]
181    InvalidRootCert,
182    #[error("failed to convert VMGSID data")]
183    InvalidVmgsidData(#[source] std::str::Utf8Error),
184    #[error("failed to parse VMGSID seed data")]
185    ParseVmgsidSeedData,
186    #[error("failed to decode VMGSID seed data")]
187    DecodeVmgsidData(#[source] hex::FromHexError),
188    #[error("X509 certificate error")]
189    X509Error(#[source] crypto::x509::X509Error),
190    #[error("SP800-108 KDF error")]
191    KdfError(#[source] crypto::kbkdf::KbkdfError),
192    #[error("failed to parse VMGSID")]
193    ParseVmgsid(#[source] guid::ParseError),
194}
195
196// Operation types for provisioning telemetry.
197#[derive(Debug)]
198enum LogOpType {
199    BeginDecryptVmgs,
200    DecryptVmgs,
201    ConvertEncryptionType,
202}
203
204/// Label used by `derive_key`
205const VMGS_KEY_DERIVE_LABEL: &[u8; 7] = b"VMGSKEY";
206
207/// KBKDF from SP800-108, using HMAC-SHA-256.
208fn derive_key(
209    key: &[u8],
210    context: &[u8],
211    label: &[u8],
212) -> Result<[u8; AES_GCM_KEY_LENGTH], crypto::kbkdf::KbkdfError> {
213    let output = crypto::kbkdf::kbkdf_hmac_sha256(key, context, label, AES_GCM_KEY_LENGTH)?;
214    Ok(output.try_into().unwrap())
215}
216
217#[derive(Debug)]
218struct Keys {
219    ingress: [u8; AES_GCM_KEY_LENGTH],
220    decrypt_egress: Option<[u8; AES_GCM_KEY_LENGTH]>,
221    encrypt_egress: [u8; AES_GCM_KEY_LENGTH],
222}
223
224/// Key protector settings
225#[derive(Clone, Copy)]
226struct KeyProtectorSettings {
227    /// Whether to update key protector
228    should_write_kp: bool,
229    /// Whether GSP by id is used
230    use_gsp_by_id: bool,
231    /// Whether hardware key sealing is used
232    use_hardware_unlock: bool,
233    /// GSP type used for decryption (for logging)
234    decrypt_gsp_type: GspType,
235    /// GSP type used for encryption (for logging)
236    encrypt_gsp_type: GspType,
237}
238
239/// Helper struct for [`protocol::vmgs::KeyProtectorById`]
240struct KeyProtectorById {
241    /// The instance of [`protocol::vmgs::KeyProtectorById`].
242    pub inner: openhcl_attestation_protocol::vmgs::KeyProtectorById,
243    /// Indicate if the instance is read from the VMGS file.
244    pub found_id: bool,
245}
246
247/// Host attestation settings obtained via the GET GSP call-out.
248pub struct HostAttestationSettings {
249    /// Whether refreshing tpm seeds is needed.
250    pub refresh_tpm_seeds: bool,
251}
252
253/// The return values of [`get_derived_keys`].
254struct DerivedKeyResult {
255    /// Optional derived keys.
256    derived_keys: Option<Keys>,
257    /// The instance of [`KeyProtectorSettings`].
258    key_protector_settings: KeyProtectorSettings,
259    /// The instance of [`GspExtendedStatusFlags`] returned by GSP.
260    gsp_extended_status_flags: GspExtendedStatusFlags,
261}
262
263/// The return values of [`initialize_platform_security`].
264pub struct PlatformAttestationData {
265    /// The instance of [`HostAttestationSettings`].
266    pub host_attestation_settings: HostAttestationSettings,
267    /// The agent data used by an attestation request.
268    pub agent_data: Option<Vec<u8>>,
269    /// The guest secret key.
270    pub guest_secret_key: Option<Vec<u8>>,
271}
272
273/// The attestation type to use.
274// TODO: Support VBS
275#[derive(Debug, MeshPayload, Copy, Clone, PartialEq, Eq)]
276pub enum AttestationType {
277    /// Use the SEV-SNP TEE for attestation.
278    Snp,
279    /// Use the TDX TEE for attestation.
280    Tdx,
281    /// Use the VBS TEE for attestation.
282    Vbs,
283    /// Use the CCA TEE for attestation,
284    Cca,
285    /// Use trusted host-based attestation.
286    Host,
287}
288
289/// Request VMGS encryption keys and unlock the VMGS.
290/// If successful, return a bool indicating whether igvmagent requested a
291/// state refresh. If unsuccessful, return an error and a bool indicating
292/// whether to retry.
293async fn try_unlock_vmgs(
294    get: &GuestEmulationTransportClient,
295    bios_guid: Guid,
296    attestation_vm_config: &AttestationVmConfig,
297    vmgs: &mut Vmgs,
298    tee_call: Option<&dyn TeeCall>,
299    guest_state_encryption_policy: GuestStateEncryptionPolicy,
300    strict_encryption_policy: bool,
301    agent_data: &mut [u8; AGENT_DATA_MAX_SIZE],
302    key_protector_by_id: &mut KeyProtectorById,
303) -> Result<bool, (AttestationErrorInner, bool)> {
304    let skr_response = if let Some(tee_call) = tee_call {
305        tracing::info!(CVM_ALLOWED, "Retrieving key-encryption key");
306
307        // Retrieve the tenant key via attestation
308        secure_key_release::request_vmgs_encryption_keys(
309            get,
310            tee_call,
311            vmgs,
312            attestation_vm_config,
313            agent_data,
314        )
315        .await
316    } else {
317        tracing::info!(CVM_ALLOWED, "Key-encryption key retrieval not required");
318
319        // Attestation is unavailable, assume no tenant key
320        Ok(VmgsEncryptionKeys::default())
321    };
322
323    let retry = match &skr_response {
324        Ok(_) => false,
325        Err((_, r)) => *r,
326    };
327
328    let skip_hw_unsealing = matches!(
329        &skr_response,
330        Err((
331            secure_key_release::RequestVmgsEncryptionKeysError::ParseIgvmAttestKeyReleaseResponse(
332                igvm_attest::key_release::KeyReleaseError::ParseHeader(
333                    igvm_attest::Error::Attestation {
334                        skip_hw_unsealing_signal: true,
335                        ..
336                    },
337                ),
338            ),
339            _,
340        ))
341    );
342
343    let VmgsEncryptionKeys {
344        ingress_rsa_kek,
345        wrapped_des_key,
346        tcb_version,
347    } = match skr_response {
348        Ok(k) => {
349            tracing::info!(CVM_ALLOWED, "Successfully retrieved key-encryption key");
350            k
351        }
352        Err((e, _)) => {
353            // Non-fatal, allowing for hardware-based recovery
354            tracing::error!(
355                CVM_ALLOWED,
356                error = &e as &dyn std::error::Error,
357                "Failed to retrieve key-encryption key"
358            );
359
360            VmgsEncryptionKeys::default()
361        }
362    };
363
364    // Determine the minimal size of a DEK entry based on whether `wrapped_des_key` presents
365    let dek_minimal_size = if wrapped_des_key.is_some() {
366        key_protector::AES_WRAPPED_AES_KEY_LENGTH
367    } else {
368        key_protector::RSA_WRAPPED_AES_KEY_LENGTH
369    };
370
371    // Read Key Protector blob from VMGS
372    tracing::info!(
373        CVM_ALLOWED,
374        dek_minimal_size = dek_minimal_size,
375        "Reading key protector from VMGS"
376    );
377    let mut key_protector = vmgs::read_key_protector(vmgs, dek_minimal_size)
378        .await
379        .map_err(|e| (AttestationErrorInner::ReadKeyProtector(e), false))?;
380
381    let start_time = std::time::SystemTime::now();
382    let vmgs_encrypted = vmgs.encrypted();
383    tracing::info!(
384        ?tcb_version,
385        vmgs_encrypted,
386        op_type = ?LogOpType::BeginDecryptVmgs,
387        "Deriving keys"
388    );
389
390    let derived_keys_result = get_derived_keys(
391        get,
392        tee_call,
393        vmgs,
394        &mut key_protector,
395        key_protector_by_id,
396        bios_guid,
397        attestation_vm_config,
398        vmgs_encrypted,
399        ingress_rsa_kek.as_ref(),
400        wrapped_des_key.as_deref(),
401        tcb_version,
402        guest_state_encryption_policy,
403        strict_encryption_policy,
404        skip_hw_unsealing,
405    )
406    .await
407    .map_err(|e| {
408        tracing::error!(
409            CVM_ALLOWED,
410            op_type = ?LogOpType::DecryptVmgs,
411            success = false,
412            err = &e as &dyn std::error::Error,
413            latency = std::time::SystemTime::now()
414                .duration_since(start_time)
415                .map_or(0, |d| d.as_millis()),
416            "Failed to derive keys"
417        );
418        (AttestationErrorInner::GetDerivedKeys(e), retry)
419    })?;
420
421    // All Underhill VMs use VMGS encryption
422    tracing::info!("Unlocking VMGS");
423    if let Err(e) = unlock_vmgs_data_store(
424        vmgs,
425        vmgs_encrypted,
426        &mut key_protector,
427        key_protector_by_id,
428        derived_keys_result.derived_keys,
429        derived_keys_result.key_protector_settings,
430        bios_guid,
431    )
432    .await
433    {
434        tracing::error!(
435            CVM_ALLOWED,
436            op_type = ?LogOpType::DecryptVmgs,
437            success = false,
438            err = &e as &dyn std::error::Error,
439            latency = std::time::SystemTime::now()
440                .duration_since(start_time)
441                .map_or(0, |d| d.as_millis()),
442            "Failed to unlock datastore"
443        );
444        get.event_log_fatal(guest_emulation_transport::api::EventLogId::ATTESTATION_FAILED)
445            .await;
446
447        Err((AttestationErrorInner::UnlockVmgsDataStore(e), retry))?;
448    }
449
450    tracing::info!(
451        CVM_ALLOWED,
452        op_type = ?LogOpType::DecryptVmgs,
453        success = true,
454        decrypt_gsp_type = ?derived_keys_result
455            .key_protector_settings
456            .decrypt_gsp_type,
457        encrypt_gsp_type = ?derived_keys_result
458            .key_protector_settings
459            .encrypt_gsp_type,
460        latency = std::time::SystemTime::now().duration_since(start_time).map_or(0, |d| d.as_millis()),
461        "Unlocked datastore"
462    );
463
464    Ok(derived_keys_result
465        .gsp_extended_status_flags
466        .state_refresh_request())
467}
468
469/// If required, attest platform. Gets VMGS datastore key.
470///
471/// Returns `refresh_tpm_seeds` (the host side GSP service indicating
472/// whether certain state needs to be updated), along with the fully
473/// initialized VMGS client.
474pub async fn initialize_platform_security(
475    get: &GuestEmulationTransportClient,
476    bios_guid: Guid,
477    attestation_vm_config: &AttestationVmConfig,
478    vmgs: &mut Vmgs,
479    tee_call: Option<&dyn TeeCall>,
480    suppress_attestation: bool,
481    driver: LocalDriver,
482    guest_state_encryption_policy: GuestStateEncryptionPolicy,
483    strict_encryption_policy: bool,
484) -> Result<PlatformAttestationData, Error> {
485    const MAXIMUM_RETRY_COUNT: usize = 10;
486    const NO_RETRY_COUNT: usize = 1;
487
488    tracing::info!(CVM_ALLOWED,
489        tee_type=?tee_call.map(|tee| tee.tee_type()),
490        secure_boot=attestation_vm_config.secure_boot,
491        tpm_enabled=attestation_vm_config.tpm_enabled,
492        tpm_persisted=attestation_vm_config.tpm_persisted,
493        "Reading security profile");
494
495    // Read Security Profile from VMGS
496    // Currently this only includes "Key Reference" data, which is not attested data, is opaque to the
497    // OpenHCL, and is passed to the IGVMm agent outside of the report contents.
498    let SecurityProfile { mut agent_data } = vmgs::read_security_profile(vmgs)
499        .await
500        .map_err(AttestationErrorInner::ReadSecurityProfile)?;
501
502    // If attestation is suppressed, return the `agent_data` that is required by
503    // TPM AK cert request.
504    if suppress_attestation {
505        tracing::info!(CVM_ALLOWED, "Suppressing attestation");
506
507        return Ok(PlatformAttestationData {
508            host_attestation_settings: HostAttestationSettings {
509                refresh_tpm_seeds: false,
510            },
511            agent_data: Some(agent_data.to_vec()),
512            guest_secret_key: None,
513        });
514    }
515
516    // Read VM id from VMGS
517    tracing::info!(CVM_ALLOWED, "Reading VM ID from VMGS");
518    let mut key_protector_by_id = match vmgs::read_key_protector_by_id(vmgs).await {
519        Ok(key_protector_by_id) => KeyProtectorById {
520            inner: key_protector_by_id,
521            found_id: true,
522        },
523        Err(vmgs::ReadFromVmgsError::EntryNotFound(_)) => KeyProtectorById {
524            inner: openhcl_attestation_protocol::vmgs::KeyProtectorById::new_zeroed(),
525            found_id: false,
526        },
527        Err(e) => { Err(AttestationErrorInner::ReadKeyProtectorById(e)) }?,
528    };
529
530    // Check if the VM id has been changed since last boot with KP write
531    let vm_id_changed = if key_protector_by_id.found_id {
532        let changed = key_protector_by_id.inner.id_guid != bios_guid;
533        if changed {
534            tracing::info!("VM Id has changed since last boot");
535        };
536        changed
537    } else {
538        // Previous id in KP not found means this is the first boot or the GspById
539        // is not provisioned, treat id as unchanged for this case.
540        false
541    };
542
543    // Retry attestation call-out if necessary (if VMGS encrypted).
544    // The IGVm Agent could be down for servicing, or the TDX service VM might not be ready, or a dynamic firmware
545    // update could mean that the report was not verifiable.
546    let vmgs_encrypted: bool = vmgs.encrypted();
547    let max_retry = if vmgs_encrypted {
548        MAXIMUM_RETRY_COUNT
549    } else {
550        NO_RETRY_COUNT
551    };
552
553    let mut timer = pal_async::timer::PolledTimer::new(&driver);
554    let mut i = 0;
555
556    let state_refresh_request_from_gsp = loop {
557        tracing::info!(CVM_ALLOWED, attempt = i, "attempt to unlock VMGS file");
558
559        let response = try_unlock_vmgs(
560            get,
561            bios_guid,
562            attestation_vm_config,
563            vmgs,
564            tee_call,
565            guest_state_encryption_policy,
566            strict_encryption_policy,
567            &mut agent_data,
568            &mut key_protector_by_id,
569        )
570        .await;
571
572        match response {
573            Ok(b) => break b,
574            Err((e, false)) => Err(e)?,
575            Err((e, true)) => {
576                if i >= max_retry - 1 {
577                    Err(e)?
578                }
579            }
580        }
581
582        // Stall on retries
583        timer.sleep(std::time::Duration::new(1, 0)).await;
584        i += 1;
585    };
586
587    let host_attestation_settings = HostAttestationSettings {
588        refresh_tpm_seeds: { state_refresh_request_from_gsp | vm_id_changed },
589    };
590
591    tracing::info!(
592        CVM_ALLOWED,
593        state_refresh_request_from_gsp = state_refresh_request_from_gsp,
594        vm_id_changed = vm_id_changed,
595        "determine if refreshing tpm seeds is needed"
596    );
597
598    // Read guest secret key from unlocked VMGS
599    let guest_secret_key = match vmgs::read_guest_secret_key(vmgs).await {
600        Ok(data) => Some(data.guest_secret_key.to_vec()),
601        Err(vmgs::ReadFromVmgsError::EntryNotFound(_)) => None,
602        Err(e) => return Err(AttestationErrorInner::ReadGuestSecretKey(e).into()),
603    };
604
605    Ok(PlatformAttestationData {
606        host_attestation_settings,
607        agent_data: Some(agent_data.to_vec()),
608        guest_secret_key,
609    })
610}
611
612/// Get ingress and egress keys for the VMGS, unlock VMGS,
613/// remove old key if necessary, and update KP.
614/// If key rolling did not complete successfully last time, there may be an
615/// old egress key in the VMGS, whose contents can be controlled by the host.
616/// This key can be used to attempt decryption but must not be used to
617/// re-encrypt the VMGS.
618async fn unlock_vmgs_data_store(
619    vmgs: &mut Vmgs,
620    vmgs_encrypted: bool,
621    key_protector: &mut KeyProtector,
622    key_protector_by_id: &mut KeyProtectorById,
623    derived_keys: Option<Keys>,
624    key_protector_settings: KeyProtectorSettings,
625    bios_guid: Guid,
626) -> Result<(), UnlockVmgsDataStoreError> {
627    let mut new_key = false; // Indicate if we need to add a new key after unlock
628
629    let Some(Keys {
630        ingress: new_ingress_key,
631        decrypt_egress: old_egress_key,
632        encrypt_egress: new_egress_key,
633    }) = derived_keys
634    else {
635        tracing::info!(
636            CVM_ALLOWED,
637            "Encryption disabled, skipping unlock vmgs data store"
638        );
639        return Ok(());
640    };
641
642    if !constant_time_eq::constant_time_eq_32(&new_ingress_key, &new_egress_key) {
643        tracing::trace!(CVM_ALLOWED, "EgressKey is different than IngressKey");
644        new_key = true;
645    }
646
647    // Call unlock_with_encryption_key using ingress_key if datastore is encrypted
648    let mut provision = false;
649    if vmgs_encrypted {
650        tracing::info!(CVM_ALLOWED, "Decrypting vmgs file...");
651        if let Err(e) = vmgs.unlock_with_encryption_key(&new_ingress_key).await {
652            if let Some(key) = old_egress_key {
653                // Key rolling did not complete successfully last time and there's an old
654                // egress key in the VMGS. It may be needed for decryption.
655                tracing::info!(CVM_ALLOWED, "Old EgressKey found");
656                vmgs.unlock_with_encryption_key(&key)
657                    .await
658                    .map_err(UnlockVmgsDataStoreError::VmgsUnlockUsingExistingEgressKey)?;
659            } else {
660                Err(UnlockVmgsDataStoreError::VmgsUnlockUsingExistingIngressKey(
661                    e,
662                ))?
663            }
664        }
665    } else {
666        // The datastore is not encrypted which means it's during provision.
667        tracing::info!(
668            CVM_ALLOWED,
669            "vmgs data store is not encrypted, provisioning."
670        );
671        provision = true;
672    }
673
674    tracing::info!(
675        CVM_ALLOWED,
676        should_write_kp = key_protector_settings.should_write_kp,
677        use_gsp_by_id = key_protector_settings.use_gsp_by_id,
678        use_hardware_unlock = key_protector_settings.use_hardware_unlock,
679        "key protector settings"
680    );
681
682    if key_protector_settings.should_write_kp {
683        // Update on disk KP with all seeds used, to allow for disaster recovery
684        vmgs::write_key_protector(key_protector, vmgs)
685            .await
686            .map_err(UnlockVmgsDataStoreError::WriteKeyProtector)?;
687
688        if key_protector_settings.use_gsp_by_id {
689            vmgs::write_key_protector_by_id(&mut key_protector_by_id.inner, vmgs, false, bios_guid)
690                .await
691                .map_err(UnlockVmgsDataStoreError::WriteKeyProtectorById)?;
692        }
693    }
694
695    if provision || new_key {
696        // Add the new egress key. If we are not provisioning, then this will
697        // also remove the old key. This will also remove the inactive key if
698        // last time we failed to remove it.
699        vmgs.update_encryption_key(&new_egress_key, EncryptionAlgorithm::AES_GCM)
700            .await
701            .map_err(UnlockVmgsDataStoreError::UpdateVmgsEncryptionKey)?;
702    }
703
704    // Persist KP to VMGS
705    persist_all_key_protectors(
706        vmgs,
707        key_protector,
708        key_protector_by_id,
709        bios_guid,
710        key_protector_settings,
711    )
712    .await
713    .map_err(UnlockVmgsDataStoreError::PersistAllKeyProtectors)
714}
715
716/// Update data store keys with key protectors.
717///         VMGS encryption can come from combinations of three sources,
718///         a Tenant Key (KEK), GSP, and GSP By Id.
719///         There is an Ingress Key (previously used to lock the VMGS),
720///         and an Egress Key (new key for locking the VMGS), and these
721///         keys can be derived differently, where KEK is
722///         always used if available, and GSP is preferred to GSP By Id.
723///         Ingress                     Possible Egress in order of preference [Ingress]
724///         - No Encryption             - All
725///         - GSP By Id                 - KEK + GSP, KEK + GSP By Id, GSP, [GSP By Id]
726///         - GSP (v10 VM and later)    - KEK + GSP, [GSP]
727///         - KEK (IVM only)            - KEK + GSP, KEK + GSP By Id, [KEK]
728///         - KEK + GSP By Id           - KEK + GSP, [KEK + GSP By Id]
729///         - KEK + GSP                 - [KEK + GSP]
730///
731/// NOTE: for TVM parity, only None, Gsp By Id v9.1, and Gsp By Id / Gsp v10.0 are used.
732async fn get_derived_keys(
733    get: &GuestEmulationTransportClient,
734    tee_call: Option<&dyn TeeCall>,
735    vmgs: &mut Vmgs,
736    key_protector: &mut KeyProtector,
737    key_protector_by_id: &mut KeyProtectorById,
738    bios_guid: Guid,
739    attestation_vm_config: &AttestationVmConfig,
740    is_encrypted: bool,
741    ingress_rsa_kek: Option<&RsaKeyPair>,
742    wrapped_des_key: Option<&[u8]>,
743    tcb_version: Option<u64>,
744    guest_state_encryption_policy: GuestStateEncryptionPolicy,
745    strict_encryption_policy: bool,
746    skip_hw_unsealing: bool,
747) -> Result<DerivedKeyResult, GetDerivedKeysError> {
748    tracing::info!(
749        CVM_ALLOWED,
750        ?guest_state_encryption_policy,
751        strict_encryption_policy,
752        "encryption policy"
753    );
754
755    // TODO: implement hardware sealing only
756    if matches!(
757        guest_state_encryption_policy,
758        GuestStateEncryptionPolicy::HardwareSealing
759    ) {
760        todo!("hardware sealing")
761    }
762
763    let mut key_protector_settings = KeyProtectorSettings {
764        should_write_kp: true,
765        use_gsp_by_id: false,
766        use_hardware_unlock: false,
767        decrypt_gsp_type: GspType::None,
768        encrypt_gsp_type: GspType::None,
769    };
770
771    let mut derived_keys = Keys {
772        ingress: [0u8; AES_GCM_KEY_LENGTH],
773        decrypt_egress: None,
774        encrypt_egress: [0u8; AES_GCM_KEY_LENGTH],
775    };
776
777    // Ingress / Egress seed values depend on what happened previously to the datastore
778    let ingress_idx = (key_protector.active_kp % 2) as usize;
779    let egress_idx = if ingress_idx == 0 { 1 } else { 0 } as usize;
780
781    let found_dek = !key_protector.dek[ingress_idx]
782        .dek_buffer
783        .iter()
784        .all(|&x| x == 0);
785
786    // Handle key released via attestation process (tenant key) to get keys from KeyProtector
787    let (ingress_key, mut decrypt_egress_key, encrypt_egress_key, no_kek) =
788        if let Some(ingress_kek) = ingress_rsa_kek {
789            let keys = match key_protector.unwrap_and_rotate_keys(
790                ingress_kek,
791                wrapped_des_key,
792                ingress_idx,
793                egress_idx,
794            ) {
795                Ok(keys) => keys,
796                Err(e)
797                    if matches!(
798                        e,
799                        GetKeysFromKeyProtectorError::DesKeyRsaUnwrap(_)
800                            | GetKeysFromKeyProtectorError::IngressDekRsaUnwrap(_)
801                    ) =>
802                {
803                    get.event_log_fatal(
804                        guest_emulation_transport::api::EventLogId::DEK_DECRYPTION_FAILED,
805                    )
806                    .await;
807
808                    return Err(GetDerivedKeysError::GetKeysFromKeyProtector(e));
809                }
810                Err(e) => return Err(GetDerivedKeysError::GetKeysFromKeyProtector(e)),
811            };
812            (
813                keys.ingress,
814                keys.decrypt_egress,
815                keys.encrypt_egress,
816                false,
817            )
818        } else {
819            (
820                [0u8; AES_GCM_KEY_LENGTH],
821                None,
822                [0u8; AES_GCM_KEY_LENGTH],
823                true,
824            )
825        };
826
827    // Handle various sources of Guest State Protection
828    let existing_unencrypted = !vmgs.encrypted() && !vmgs.was_provisioned_this_boot();
829    let is_gsp_by_id = key_protector_by_id.found_id && key_protector_by_id.inner.ported != 1;
830    let is_gsp = key_protector.gsp[ingress_idx].gsp_length != 0;
831    tracing::info!(
832        CVM_ALLOWED,
833        is_encrypted,
834        is_gsp_by_id,
835        is_gsp,
836        found_dek,
837        "initial vmgs encryption state"
838    );
839    let mut requires_gsp_by_id = is_gsp_by_id;
840
841    // Attempt GSP
842    let (gsp_response, gsp_available, no_gsp, requires_gsp) = {
843        tracing::info!(CVM_ALLOWED, "attempting GSP");
844
845        let response = get_gsp_data(get, key_protector).await;
846
847        tracing::info!(
848            CVM_ALLOWED,
849            request_data_length_in_vmgs = key_protector.gsp[ingress_idx].gsp_length,
850            no_rpc_server = response.extended_status_flags.no_rpc_server(),
851            requires_rpc_server = response.extended_status_flags.requires_rpc_server(),
852            encrypted_gsp_length = response.encrypted_gsp.length,
853            "GSP response"
854        );
855
856        let no_gsp_available =
857            response.extended_status_flags.no_rpc_server() || response.encrypted_gsp.length == 0;
858
859        let no_gsp = no_gsp_available
860            // disable if auto and pre-existing guest state is not encrypted or
861            // encrypted using GspById to prevent encryption changes without
862            // explicit intent
863            || (matches!(
864                guest_state_encryption_policy,
865                GuestStateEncryptionPolicy::Auto
866            ) && (is_gsp_by_id || existing_unencrypted))
867            // disable per encryption policy (first boot only, unless strict)
868            || (matches!(
869                guest_state_encryption_policy,
870                GuestStateEncryptionPolicy::GspById | GuestStateEncryptionPolicy::None
871            ) && (!is_gsp || strict_encryption_policy));
872
873        let requires_gsp = is_gsp
874            || response.extended_status_flags.requires_rpc_server()
875            || (matches!(
876                guest_state_encryption_policy,
877                GuestStateEncryptionPolicy::GspKey
878            ) && strict_encryption_policy);
879
880        // If the VMGS is encrypted, but no key protection data is found,
881        // assume GspById encryption is enabled, but no ID file was written.
882        if is_encrypted && !requires_gsp_by_id && !requires_gsp && !found_dek {
883            requires_gsp_by_id = true;
884        }
885
886        (response, !no_gsp_available, no_gsp, requires_gsp)
887    };
888
889    // Attempt GSP By Id protection if GSP is not available, when changing
890    // schemes, or as requested
891    let (gsp_response_by_id, gsp_by_id_available, no_gsp_by_id) = if no_gsp || requires_gsp_by_id {
892        tracing::info!(CVM_ALLOWED, "attempting GSP By Id");
893
894        let gsp_response_by_id = get
895            .guest_state_protection_data_by_id()
896            .await
897            .map_err(GetDerivedKeysError::FetchGuestStateProtectionById)?;
898
899        let no_gsp_by_id_available = gsp_response_by_id.extended_status_flags.no_registry_file();
900
901        let no_gsp_by_id = no_gsp_by_id_available
902            // disable if auto and pre-existing guest state is unencrypted
903            // to prevent encryption changes without explicit intent
904            || (matches!(
905                guest_state_encryption_policy,
906                GuestStateEncryptionPolicy::Auto
907            ) && existing_unencrypted)
908            // disable per encryption policy (first boot only, unless strict)
909            || (matches!(
910                guest_state_encryption_policy,
911                GuestStateEncryptionPolicy::None
912            ) && (!requires_gsp_by_id || strict_encryption_policy));
913
914        if no_gsp_by_id && requires_gsp_by_id {
915            Err(GetDerivedKeysError::GspByIdRequiredButNotFound)?
916        }
917
918        (
919            gsp_response_by_id,
920            Some(!no_gsp_by_id_available),
921            no_gsp_by_id,
922        )
923    } else {
924        (GuestStateProtectionById::new_zeroed(), None, true)
925    };
926
927    // If sources of encryption used last are missing, attempt to unseal VMGS key with hardware key
928    if (no_kek && found_dek) || (no_gsp && requires_gsp) || (no_gsp_by_id && requires_gsp_by_id) {
929        // If possible, get ingressKey from hardware sealed data
930        let (hardware_key_protector, hardware_derived_keys) = if let Some(tee_call) = tee_call {
931            let hardware_key_protector = match vmgs::read_hardware_key_protector(vmgs).await {
932                Ok(hardware_key_protector) => Some(hardware_key_protector),
933                Err(e) => {
934                    // non-fatal
935                    tracing::warn!(
936                        CVM_ALLOWED,
937                        error = &e as &dyn std::error::Error,
938                        "failed to read HW_KEY_PROTECTOR from Vmgs"
939                    );
940                    None
941                }
942            };
943
944            let hardware_derived_keys = tee_call.supports_get_derived_key().and_then(|tee_call| {
945                if let Some(hardware_key_protector) = &hardware_key_protector {
946                    match HardwareDerivedKeys::derive_key(
947                        tee_call,
948                        attestation_vm_config,
949                        hardware_key_protector.header.tcb_version,
950                    ) {
951                        Ok(hardware_derived_key) => Some(hardware_derived_key),
952                        Err(e) => {
953                            // non-fatal
954                            tracing::warn!(
955                                CVM_ALLOWED,
956                                error = &e as &dyn std::error::Error,
957                                "failed to derive hardware keys using HW_KEY_PROTECTOR",
958                            );
959                            None
960                        }
961                    }
962                } else {
963                    None
964                }
965            });
966
967            // When the IGVM agent signals skip_hw_unsealing, set both
968            // hardware_key_protector and hardware_derived_keys to None
969            // so the code falls through to the scheme-specific error below.
970            // When hardware sealing keys were actually available, additionally
971            // emit a warning and a host event that make the skip visible.
972            if skip_hw_unsealing {
973                if hardware_key_protector.is_some() && hardware_derived_keys.is_some() {
974                    tracing::warn!(
975                        CVM_ALLOWED,
976                        "Skipping hardware unsealing of VMGS DEK as signaled by IGVM agent"
977                    );
978                    get.event_log_fatal(
979                        guest_emulation_transport::api::EventLogId::DEK_HARDWARE_UNSEALING_SKIPPED,
980                    )
981                    .await;
982
983                    (None, None)
984                } else {
985                    tracing::info!(
986                        CVM_ALLOWED,
987                        hardware_key_protector = hardware_key_protector.is_some(),
988                        hardware_derived_keys = hardware_derived_keys.is_some(),
989                        "skip_hw_unsealing signaled but hardware key data not available, \
990                         falling through to scheme-specific error"
991                    );
992                    (None, None)
993                }
994            } else {
995                (hardware_key_protector, hardware_derived_keys)
996            }
997        } else {
998            (None, None)
999        };
1000
1001        if let (Some(hardware_key_protector), Some(hardware_derived_keys)) =
1002            (hardware_key_protector, hardware_derived_keys)
1003        {
1004            derived_keys.ingress = hardware_key_protector
1005                .unseal_key(&hardware_derived_keys)
1006                .map_err(GetDerivedKeysError::UnsealIngressKeyUsingHardwareDerivedKeys)?;
1007            derived_keys.decrypt_egress = None;
1008            derived_keys.encrypt_egress = derived_keys.ingress;
1009
1010            key_protector_settings.should_write_kp = false;
1011            key_protector_settings.use_hardware_unlock = true;
1012
1013            tracing::warn!(
1014                CVM_ALLOWED,
1015                "Using hardware-derived key to recover VMGS DEK"
1016            );
1017
1018            return Ok(DerivedKeyResult {
1019                derived_keys: Some(derived_keys),
1020                key_protector_settings,
1021                gsp_extended_status_flags: gsp_response.extended_status_flags,
1022            });
1023        } else {
1024            if no_kek && found_dek {
1025                return Err(GetDerivedKeysError::GetIngressKeyFromKpFailed);
1026            } else if no_gsp && requires_gsp {
1027                return Err(GetDerivedKeysError::GetIngressKeyFromKGspFailed);
1028            } else {
1029                // no_gsp_by_id && requires_gsp_by_id
1030                return Err(GetDerivedKeysError::GetIngressKeyFromKGspByIdFailed);
1031            }
1032        }
1033    }
1034
1035    tracing::info!(
1036        CVM_ALLOWED,
1037        kek = !no_kek,
1038        gsp_available,
1039        gsp = !no_gsp,
1040        gsp_by_id_available = ?gsp_by_id_available,
1041        gsp_by_id = !no_gsp_by_id,
1042        "Encryption sources"
1043    );
1044
1045    // Check if sources of encryption are available
1046    if no_kek && no_gsp && no_gsp_by_id {
1047        if is_encrypted {
1048            Err(GetDerivedKeysError::DisableVmgsEncryptionFailed)?
1049        }
1050        match guest_state_encryption_policy {
1051            // fail if some minimum level of encryption was required
1052            GuestStateEncryptionPolicy::GspById
1053            | GuestStateEncryptionPolicy::GspKey
1054            | GuestStateEncryptionPolicy::HardwareSealing => {
1055                Err(GetDerivedKeysError::EncryptionRequiredButNotFound)?
1056            }
1057            GuestStateEncryptionPolicy::Auto | GuestStateEncryptionPolicy::None => {
1058                tracing::info!(CVM_ALLOWED, "No VMGS encryption used.");
1059
1060                return Ok(DerivedKeyResult {
1061                    derived_keys: None,
1062                    key_protector_settings,
1063                    gsp_extended_status_flags: gsp_response.extended_status_flags,
1064                });
1065            }
1066        }
1067    }
1068
1069    // Attempt to get hardware derived keys
1070    let hardware_derived_keys = tee_call
1071        .and_then(|tee_call| tee_call.supports_get_derived_key())
1072        .and_then(|tee_call| {
1073            if let Some(tcb_version) = tcb_version {
1074                match HardwareDerivedKeys::derive_key(tee_call, attestation_vm_config, tcb_version)
1075                {
1076                    Ok(keys) => Some(keys),
1077                    Err(e) => {
1078                        // non-fatal
1079                        tracing::warn!(
1080                            CVM_ALLOWED,
1081                            error = &e as &dyn std::error::Error,
1082                            "failed to derive hardware keys"
1083                        );
1084                        None
1085                    }
1086                }
1087            } else {
1088                None
1089            }
1090        });
1091
1092    // Use tenant key (KEK only)
1093    if no_gsp && no_gsp_by_id {
1094        tracing::info!(CVM_ALLOWED, "No GSP used with SKR");
1095
1096        derived_keys.ingress = ingress_key;
1097        derived_keys.decrypt_egress = decrypt_egress_key;
1098        derived_keys.encrypt_egress = encrypt_egress_key;
1099
1100        if let Some(hardware_derived_keys) = hardware_derived_keys {
1101            let hardware_key_protector = HardwareKeyProtector::seal_key(
1102                &hardware_derived_keys,
1103                &derived_keys.encrypt_egress,
1104            )
1105            .map_err(GetDerivedKeysError::SealEgressKeyUsingHardwareDerivedKeys)?;
1106            vmgs::write_hardware_key_protector(&hardware_key_protector, vmgs)
1107                .await
1108                .map_err(GetDerivedKeysError::VmgsWriteHardwareKeyProtector)?;
1109
1110            tracing::info!(CVM_ALLOWED, "hardware key protector updated (no GSP used)");
1111        }
1112
1113        return Ok(DerivedKeyResult {
1114            derived_keys: Some(derived_keys),
1115            key_protector_settings,
1116            gsp_extended_status_flags: gsp_response.extended_status_flags,
1117        });
1118    }
1119
1120    // GSP By Id derives keys differently,
1121    // because key is shared across VMs different context must be used (Id GUID)
1122    if (no_kek && no_gsp) || requires_gsp_by_id {
1123        let derived_keys_by_id =
1124            get_derived_keys_by_id(key_protector_by_id, bios_guid, gsp_response_by_id)
1125                .map_err(GetDerivedKeysError::GetDerivedKeyById)?;
1126
1127        if no_kek && no_gsp {
1128            if matches!(
1129                guest_state_encryption_policy,
1130                GuestStateEncryptionPolicy::GspById | GuestStateEncryptionPolicy::Auto
1131            ) {
1132                tracing::info!(CVM_ALLOWED, "Using GspById");
1133            } else {
1134                // Log a warning here to indicate that the VMGS state is out of
1135                // sync with the VM's configuration.
1136                //
1137                // This should only happen if strict encryption policy is
1138                // disabled and one of the following is true:
1139                // - The VM is configured to have no encryption, but it already
1140                //   has GspById encryption.
1141                // - The VM is configured to use GspKey, but GspKey is not
1142                //   available and GspById is.
1143                tracing::warn!(CVM_ALLOWED, "Allowing GspById");
1144            };
1145
1146            // Not required for Id protection
1147            key_protector_settings.should_write_kp = false;
1148            key_protector_settings.use_gsp_by_id = true;
1149            key_protector_settings.decrypt_gsp_type = GspType::GspById;
1150            key_protector_settings.encrypt_gsp_type = GspType::GspById;
1151
1152            return Ok(DerivedKeyResult {
1153                derived_keys: Some(derived_keys_by_id),
1154                key_protector_settings,
1155                gsp_extended_status_flags: gsp_response.extended_status_flags,
1156            });
1157        }
1158
1159        derived_keys.ingress = derived_keys_by_id.ingress;
1160
1161        tracing::info!(
1162            CVM_ALLOWED,
1163            op_type = ?LogOpType::ConvertEncryptionType,
1164            "Converting GSP method."
1165        );
1166    }
1167
1168    let egress_seed;
1169    let mut ingress_seed = None;
1170
1171    // To get to this point, either KEK or GSP must be available
1172    // Mix tenant key with GSP key to create data store encryption keys
1173    // Covers possible egress combinations:
1174    // GSP, GSP + KEK, GSP By Id + KEK
1175
1176    if requires_gsp_by_id || no_gsp {
1177        // If DEK exists, ingress is either KEK or KEK + GSP By Id
1178        // If no DEK, then ingress was Gsp By Id (derived above)
1179        if found_dek {
1180            if requires_gsp_by_id {
1181                ingress_seed = Some(
1182                    gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize]
1183                        .to_vec(),
1184                );
1185                key_protector_settings.decrypt_gsp_type = GspType::GspById;
1186            } else {
1187                derived_keys.ingress = ingress_key;
1188            }
1189        } else {
1190            key_protector_settings.decrypt_gsp_type = GspType::GspById;
1191        }
1192
1193        // Choose best available egress seed
1194        if no_gsp {
1195            egress_seed =
1196                gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize].to_vec();
1197            key_protector_settings.use_gsp_by_id = true;
1198            key_protector_settings.encrypt_gsp_type = GspType::GspById;
1199        } else {
1200            egress_seed =
1201                gsp_response.new_gsp.buffer[..gsp_response.new_gsp.length as usize].to_vec();
1202            key_protector_settings.encrypt_gsp_type = GspType::GspKey;
1203        }
1204    } else {
1205        // `no_gsp` is false, using `gsp_response`
1206
1207        if gsp_response.decrypted_gsp[ingress_idx].length == 0
1208            && gsp_response.decrypted_gsp[egress_idx].length == 0
1209        {
1210            tracing::info!(CVM_ALLOWED, "Applying GSP.");
1211
1212            // VMGS has never had any GSP applied.
1213            // Leave ingress key untouched, derive egress key with new seed.
1214            egress_seed =
1215                gsp_response.new_gsp.buffer[..gsp_response.new_gsp.length as usize].to_vec();
1216
1217            // Ingress key is either zero or tenant only.
1218            // Only copy in the case where a tenant key was released.
1219            if !no_kek {
1220                derived_keys.ingress = ingress_key;
1221            }
1222
1223            key_protector_settings.encrypt_gsp_type = GspType::GspKey;
1224        } else {
1225            tracing::info!(CVM_ALLOWED, "Using existing GSP.");
1226
1227            ingress_seed = Some(
1228                gsp_response.decrypted_gsp[ingress_idx].buffer
1229                    [..gsp_response.decrypted_gsp[ingress_idx].length as usize]
1230                    .to_vec(),
1231            );
1232
1233            if gsp_response.decrypted_gsp[egress_idx].length == 0 {
1234                // Derive ingress with saved seed, derive egress with new seed.
1235                egress_seed =
1236                    gsp_response.new_gsp.buffer[..gsp_response.new_gsp.length as usize].to_vec();
1237            } else {
1238                // System failed during data store unlock, and is in indeterminate state.
1239                // The egress key might have been applied, or the ingress key might be valid.
1240                // Use saved KP, derive ingress/egress keys to attempt recovery.
1241                // Do not update the saved KP with new seed value.
1242                egress_seed = gsp_response.decrypted_gsp[egress_idx].buffer
1243                    [..gsp_response.decrypted_gsp[egress_idx].length as usize]
1244                    .to_vec();
1245                key_protector_settings.should_write_kp = false;
1246                decrypt_egress_key = Some(encrypt_egress_key);
1247            }
1248
1249            key_protector_settings.decrypt_gsp_type = GspType::GspKey;
1250            key_protector_settings.encrypt_gsp_type = GspType::GspKey;
1251        }
1252    }
1253
1254    // Derive key used to lock data store previously
1255    if let Some(seed) = ingress_seed {
1256        derived_keys.ingress = derive_key(&ingress_key, &seed, VMGS_KEY_DERIVE_LABEL)
1257            .map_err(GetDerivedKeysError::DeriveIngressKey)?;
1258    }
1259
1260    // Always derive a new egress key using best available seed
1261    derived_keys.decrypt_egress = decrypt_egress_key
1262        .map(|key| derive_key(&key, &egress_seed, VMGS_KEY_DERIVE_LABEL))
1263        .transpose()
1264        .map_err(GetDerivedKeysError::DeriveEgressKey)?;
1265
1266    derived_keys.encrypt_egress =
1267        derive_key(&encrypt_egress_key, &egress_seed, VMGS_KEY_DERIVE_LABEL)
1268            .map_err(GetDerivedKeysError::DeriveEgressKey)?;
1269
1270    if key_protector_settings.should_write_kp {
1271        // Update with all seeds used, but do not write until data store is unlocked
1272        key_protector.gsp[egress_idx]
1273            .gsp_buffer
1274            .copy_from_slice(&gsp_response.encrypted_gsp.buffer);
1275        key_protector.gsp[egress_idx].gsp_length = gsp_response.encrypted_gsp.length;
1276
1277        if let Some(hardware_derived_keys) = hardware_derived_keys {
1278            let hardware_key_protector = HardwareKeyProtector::seal_key(
1279                &hardware_derived_keys,
1280                &derived_keys.encrypt_egress,
1281            )
1282            .map_err(GetDerivedKeysError::SealEgressKeyUsingHardwareDerivedKeys)?;
1283
1284            vmgs::write_hardware_key_protector(&hardware_key_protector, vmgs)
1285                .await
1286                .map_err(GetDerivedKeysError::VmgsWriteHardwareKeyProtector)?;
1287
1288            tracing::info!(CVM_ALLOWED, "hardware key protector updated");
1289        }
1290    }
1291
1292    if matches!(
1293        guest_state_encryption_policy,
1294        GuestStateEncryptionPolicy::GspKey | GuestStateEncryptionPolicy::Auto
1295    ) {
1296        tracing::info!(CVM_ALLOWED, "Using Gsp");
1297    } else {
1298        // Log a warning here to indicate that the VMGS state is out of
1299        // sync with the VM's configuration.
1300        //
1301        // This should only happen if the VM is configured to have no
1302        // encryption or GspById encryption, but it already has GspKey
1303        // encryption and strict encryption policy is disabled.
1304        tracing::warn!(CVM_ALLOWED, "Allowing Gsp");
1305    }
1306
1307    Ok(DerivedKeyResult {
1308        derived_keys: Some(derived_keys),
1309        key_protector_settings,
1310        gsp_extended_status_flags: gsp_response.extended_status_flags,
1311    })
1312}
1313
1314/// Update data store keys with key protectors based on VmUniqueId & host seed.
1315fn get_derived_keys_by_id(
1316    key_protector_by_id: &mut KeyProtectorById,
1317    bios_guid: Guid,
1318    gsp_response_by_id: GuestStateProtectionById,
1319) -> Result<Keys, GetDerivedKeysByIdError> {
1320    // This does not handle tenant encrypted VMGS files or Isolated VM,
1321    // or the case where an unlock/relock fails and a snapshot is
1322    // made from that file (the Id cannot change in that failure path).
1323    // When converted to a later scheme, Egress Key will be overwritten.
1324
1325    // Always derive a new egress key from current VmUniqueId
1326    let new_egress_key = derive_key(
1327        &gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize],
1328        bios_guid.as_bytes(),
1329        VMGS_KEY_DERIVE_LABEL,
1330    )
1331    .map_err(GetDerivedKeysByIdError::DeriveEgressKeyUsingCurrentVmId)?;
1332
1333    if new_egress_key.len() != AES_GCM_KEY_LENGTH {
1334        Err(GetDerivedKeysByIdError::InvalidDerivedEgressKeySize {
1335            key_size: new_egress_key.len(),
1336            expected_size: AES_GCM_KEY_LENGTH,
1337        })?
1338    }
1339
1340    // Ingress values depend on what happened previously to the datastore.
1341    // If not previously encrypted (no saved Id), then Ingress Key not required.
1342    let new_ingress_key = if key_protector_by_id.inner.id_guid != Guid::default() {
1343        // Derive key used to lock data store previously
1344        derive_key(
1345            &gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize],
1346            key_protector_by_id.inner.id_guid.as_bytes(),
1347            VMGS_KEY_DERIVE_LABEL,
1348        )
1349        .map_err(GetDerivedKeysByIdError::DeriveIngressKeyUsingKeyProtectorId)?
1350    } else {
1351        // If data store is not encrypted, Ingress should equal Egress
1352        new_egress_key
1353    };
1354
1355    if new_ingress_key.len() != AES_GCM_KEY_LENGTH {
1356        Err(GetDerivedKeysByIdError::InvalidDerivedIngressKeySize {
1357            key_size: new_ingress_key.len(),
1358            expected_size: AES_GCM_KEY_LENGTH,
1359        })?
1360    }
1361
1362    Ok(Keys {
1363        ingress: new_ingress_key,
1364        decrypt_egress: None,
1365        encrypt_egress: new_egress_key,
1366    })
1367}
1368
1369/// Prepare the request payload and request GSP from the host via GET.
1370async fn get_gsp_data(
1371    get: &GuestEmulationTransportClient,
1372    key_protector: &mut KeyProtector,
1373) -> GuestStateProtection {
1374    use openhcl_attestation_protocol::vmgs::GSP_BUFFER_SIZE;
1375    use openhcl_attestation_protocol::vmgs::NUMBER_KP;
1376
1377    const_assert_eq!(guest_emulation_transport::api::NUMBER_GSP, NUMBER_KP as u32);
1378    const_assert_eq!(
1379        guest_emulation_transport::api::GSP_CIPHERTEXT_MAX,
1380        GSP_BUFFER_SIZE as u32
1381    );
1382
1383    let mut encrypted_gsp =
1384        [guest_emulation_transport::api::GspCiphertextContent::new_zeroed(); NUMBER_KP];
1385
1386    for (i, gsp) in encrypted_gsp.iter_mut().enumerate().take(NUMBER_KP) {
1387        if key_protector.gsp[i].gsp_length == 0 {
1388            continue;
1389        }
1390
1391        gsp.buffer[..key_protector.gsp[i].gsp_length as usize].copy_from_slice(
1392            &key_protector.gsp[i].gsp_buffer[..key_protector.gsp[i].gsp_length as usize],
1393        );
1394
1395        gsp.length = key_protector.gsp[i].gsp_length;
1396    }
1397
1398    get.guest_state_protection_data(encrypted_gsp, GspExtendedStatusFlags::new())
1399        .await
1400}
1401
1402/// Update Key Protector to remove 2nd protector, and write to VMGS
1403async fn persist_all_key_protectors(
1404    vmgs: &mut Vmgs,
1405    key_protector: &mut KeyProtector,
1406    key_protector_by_id: &mut KeyProtectorById,
1407    bios_guid: Guid,
1408    key_protector_settings: KeyProtectorSettings,
1409) -> Result<(), PersistAllKeyProtectorsError> {
1410    use openhcl_attestation_protocol::vmgs::NUMBER_KP;
1411
1412    if key_protector_settings.use_gsp_by_id && !key_protector_settings.should_write_kp {
1413        vmgs::write_key_protector_by_id(&mut key_protector_by_id.inner, vmgs, false, bios_guid)
1414            .await
1415            .map_err(PersistAllKeyProtectorsError::WriteKeyProtectorById)?;
1416    } else {
1417        // If HW Key unlocked VMGS, do not alter KP
1418        if !key_protector_settings.use_hardware_unlock {
1419            // Remove ingress KP & DEK, no longer applies to data store
1420            key_protector.dek[key_protector.active_kp as usize % NUMBER_KP]
1421                .dek_buffer
1422                .fill(0);
1423            key_protector.gsp[key_protector.active_kp as usize % NUMBER_KP].gsp_length = 0;
1424            key_protector.active_kp += 1;
1425
1426            vmgs::write_key_protector(key_protector, vmgs)
1427                .await
1428                .map_err(PersistAllKeyProtectorsError::WriteKeyProtector)?;
1429        }
1430
1431        // Update Id data to indicate this scheme is no longer in use
1432        if !key_protector_settings.use_gsp_by_id
1433            && key_protector_by_id.found_id
1434            && key_protector_by_id.inner.ported == 0
1435        {
1436            key_protector_by_id.inner.ported = 1;
1437            vmgs::write_key_protector_by_id(&mut key_protector_by_id.inner, vmgs, true, bios_guid)
1438                .await
1439                .map_err(PersistAllKeyProtectorsError::WriteKeyProtectorById)?;
1440        }
1441    }
1442
1443    Ok(())
1444}
1445
1446#[derive(Debug, Serialize, Deserialize)]
1447struct ProvenanceJwtBody {
1448    #[serde(rename = "VMGSID")]
1449    pub vmgsid: String,
1450}
1451
1452/// Read the VMGS provenance doc and produce runtime claims
1453pub fn get_provenance_claims(prov_file: &[u8]) -> Result<VmgsProvisioner, Error> {
1454    let jwt = JwtHelper::<ProvenanceJwtBody>::from(prov_file)
1455        .map_err(ProvenanceError::DecodeProvenanceDoc)
1456        .map_err(AttestationErrorInner::Provenance)?;
1457    let valid = jwt
1458        .verify_signature()
1459        .map_err(ProvenanceError::VerifySignature)
1460        .map_err(AttestationErrorInner::Provenance)?;
1461
1462    if !valid {
1463        return Err(Error(AttestationErrorInner::Provenance(
1464            ProvenanceError::InvalidSignature,
1465        )));
1466    }
1467
1468    let cert_chain = jwt
1469        .cert_chain()
1470        .map_err(ProvenanceError::DecodeProvenanceDoc)
1471        .map_err(AttestationErrorInner::Provenance)?;
1472    let leaf = &cert_chain[0];
1473
1474    let sn = leaf
1475        .subject_common_name()
1476        .map_err(ProvenanceError::X509Error)
1477        .map_err(AttestationErrorInner::Provenance)?
1478        .ok_or(AttestationErrorInner::Provenance(
1479            ProvenanceError::MissingLeafCertSubjectName,
1480        ))?;
1481
1482    let root = cert_chain.last().ok_or(AttestationErrorInner::Provenance(
1483        ProvenanceError::InvalidRootCert,
1484    ))?;
1485    let digest = sha_256(
1486        &(root
1487            .to_der()
1488            .map_err(ProvenanceError::X509Error)
1489            .map_err(AttestationErrorInner::Provenance)?),
1490    );
1491    let signer = format!("did:x509:0:sha256:{}:subject:{}", hex::encode(digest), sn);
1492    let vmgsid = jwt.jwt.body.vmgsid;
1493
1494    Ok(VmgsProvisioner {
1495        id: Guid::parse(vmgsid.as_bytes())
1496            .map_err(ProvenanceError::ParseVmgsid)
1497            .map_err(AttestationErrorInner::Provenance)?,
1498        signer,
1499    })
1500}
1501
1502/// Derive the expected VMGSID from the encrypted seed data.
1503pub fn derive_vmgsid(seed_file: &[u8]) -> Result<Guid, Error> {
1504    let seed_file_str = str::from_utf8(seed_file)
1505        .map_err(ProvenanceError::InvalidVmgsidData)
1506        .map_err(AttestationErrorInner::Provenance)?;
1507
1508    // The seed file has four fields separated by commas, but the fourth field
1509    // is just the length of the first field. Ignore any fields beyond the first
1510    // three (so the provisioning service can change the format later without
1511    // breaking anything).
1512    let parts = seed_file_str
1513        .split(',')
1514        .map(|s| s.trim())
1515        .collect::<Vec<&str>>();
1516    if parts.len() < 3 {
1517        Err(AttestationErrorInner::Provenance(
1518            ProvenanceError::ParseVmgsidSeedData,
1519        ))?;
1520    }
1521
1522    let seed = hex::decode(parts[0])
1523        .map_err(ProvenanceError::DecodeVmgsidData)
1524        .map_err(AttestationErrorInner::Provenance)?;
1525    let label = hex::decode(parts[1])
1526        .map_err(ProvenanceError::DecodeVmgsidData)
1527        .map_err(AttestationErrorInner::Provenance)?;
1528    let context = hex::decode(parts[2])
1529        .map_err(ProvenanceError::DecodeVmgsidData)
1530        .map_err(AttestationErrorInner::Provenance)?;
1531
1532    let key = crypto::kbkdf::kbkdf_hmac_sha256(&seed, &context, &label, 32)
1533        .map_err(ProvenanceError::KdfError)
1534        .map_err(AttestationErrorInner::Provenance)?;
1535
1536    Ok(Guid::from_slice(&key[0..16].try_into().unwrap()))
1537}
1538
1539/// Module that implements the mock [`TeeCall`] for testing purposes
1540#[cfg(test)]
1541pub mod test_utils {
1542    use tee_call::GetAttestationReportResult;
1543    use tee_call::HW_DERIVED_KEY_LENGTH;
1544    use tee_call::REPORT_DATA_SIZE;
1545    use tee_call::TeeCall;
1546    use tee_call::TeeCallGetDerivedKey;
1547    use tee_call::TeeType;
1548
1549    /// Mock implementation of [`TeeCall`] with get derived key support for testing purposes
1550    pub struct MockTeeCall {
1551        /// Mock TCB version to return from get_attestation_report
1552        pub tcb_version: u64,
1553    }
1554
1555    impl MockTeeCall {
1556        /// Create a new instance of [`MockTeeCall`].
1557        pub fn new(tcb_version: u64) -> Self {
1558            Self { tcb_version }
1559        }
1560    }
1561
1562    impl TeeCall for MockTeeCall {
1563        fn get_attestation_report(
1564            &self,
1565            report_data: &[u8; REPORT_DATA_SIZE],
1566        ) -> Result<GetAttestationReportResult, tee_call::Error> {
1567            let mut report =
1568                [0x6c; openhcl_attestation_protocol::igvm_attest::get::SNP_VM_REPORT_SIZE];
1569            report[..REPORT_DATA_SIZE].copy_from_slice(report_data);
1570
1571            Ok(GetAttestationReportResult {
1572                report: report.to_vec(),
1573                tcb_version: Some(self.tcb_version),
1574            })
1575        }
1576
1577        fn supports_get_derived_key(&self) -> Option<&dyn TeeCallGetDerivedKey> {
1578            Some(self)
1579        }
1580
1581        fn tee_type(&self) -> TeeType {
1582            // Use Snp for testing
1583            TeeType::Snp
1584        }
1585    }
1586
1587    impl TeeCallGetDerivedKey for MockTeeCall {
1588        fn get_derived_key(&self, tcb_version: u64) -> Result<[u8; 32], tee_call::Error> {
1589            // Base test key; mix in policy so different policies yield different derived secrets
1590            let mut key: [u8; HW_DERIVED_KEY_LENGTH] = [0xab; HW_DERIVED_KEY_LENGTH];
1591
1592            // Use mutation to simulate the policy
1593            let tcb = tcb_version.to_le_bytes();
1594            for (i, b) in key.iter_mut().enumerate() {
1595                *b ^= tcb[i % tcb.len()];
1596            }
1597
1598            Ok(key)
1599        }
1600    }
1601
1602    /// Mock implementation of [`TeeCall`] without get derived key support for testing purposes
1603    pub struct MockTeeCallNoGetDerivedKey;
1604
1605    impl TeeCall for MockTeeCallNoGetDerivedKey {
1606        fn get_attestation_report(
1607            &self,
1608            report_data: &[u8; REPORT_DATA_SIZE],
1609        ) -> Result<GetAttestationReportResult, tee_call::Error> {
1610            let mut report =
1611                [0x6c; openhcl_attestation_protocol::igvm_attest::get::SNP_VM_REPORT_SIZE];
1612            report[..REPORT_DATA_SIZE].copy_from_slice(report_data);
1613
1614            Ok(GetAttestationReportResult {
1615                report: report.to_vec(),
1616                tcb_version: None,
1617            })
1618        }
1619
1620        fn supports_get_derived_key(&self) -> Option<&dyn TeeCallGetDerivedKey> {
1621            None
1622        }
1623
1624        fn tee_type(&self) -> TeeType {
1625            // Use Snp for testing
1626            TeeType::Snp
1627        }
1628    }
1629}
1630
1631#[cfg(test)]
1632mod tests {
1633    use super::*;
1634    use crate::test_utils::MockTeeCallNoGetDerivedKey;
1635    use disk_backend::Disk;
1636    use disklayer_ram::ram_disk;
1637    use get_protocol::GSP_CLEARTEXT_MAX;
1638    use get_protocol::GspExtendedStatusFlags;
1639    use guest_emulation_device::IgvmAgentAction;
1640    use guest_emulation_device::IgvmAgentTestPlan;
1641    use guest_emulation_transport::test_utilities::TestGet;
1642    use key_protector::AES_WRAPPED_AES_KEY_LENGTH;
1643    use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestRequestType;
1644    use openhcl_attestation_protocol::vmgs::DEK_BUFFER_SIZE;
1645    use openhcl_attestation_protocol::vmgs::DekKp;
1646    use openhcl_attestation_protocol::vmgs::GSP_BUFFER_SIZE;
1647    use openhcl_attestation_protocol::vmgs::GspKp;
1648    use openhcl_attestation_protocol::vmgs::NUMBER_KP;
1649    use pal_async::DefaultDriver;
1650    use pal_async::async_test;
1651    use pal_async::task::Spawn;
1652    use std::collections::VecDeque;
1653    use test_utils::MockTeeCall;
1654    use test_with_tracing::test;
1655    use vmgs_format::EncryptionAlgorithm;
1656    use vmgs_format::FileId;
1657
1658    const ONE_MEGA_BYTE: u64 = 1024 * 1024;
1659
1660    fn new_test_file() -> Disk {
1661        ram_disk(4 * ONE_MEGA_BYTE, false).unwrap()
1662    }
1663
1664    async fn new_formatted_vmgs() -> Vmgs {
1665        let disk = new_test_file();
1666
1667        let mut vmgs = Vmgs::format_new(disk, None).await.unwrap();
1668
1669        assert!(
1670            key_protector_is_empty(&mut vmgs).await,
1671            "Newly formatted VMGS should have an empty key protector"
1672        );
1673        assert!(
1674            key_protector_by_id_is_empty(&mut vmgs).await,
1675            "Newly formatted VMGS should have an empty key protector by id"
1676        );
1677
1678        vmgs
1679    }
1680
1681    async fn key_protector_is_empty(vmgs: &mut Vmgs) -> bool {
1682        let key_protector = vmgs::read_key_protector(vmgs, AES_WRAPPED_AES_KEY_LENGTH)
1683            .await
1684            .unwrap();
1685
1686        key_protector.as_bytes().iter().all(|&b| b == 0)
1687    }
1688
1689    async fn key_protector_by_id_is_empty(vmgs: &mut Vmgs) -> bool {
1690        vmgs::read_key_protector_by_id(vmgs)
1691            .await
1692            .is_err_and(|err| {
1693                matches!(
1694                    err,
1695                    vmgs::ReadFromVmgsError::EntryNotFound(FileId::VM_UNIQUE_ID)
1696                )
1697            })
1698    }
1699
1700    async fn hardware_key_protector_is_empty(vmgs: &mut Vmgs) -> bool {
1701        vmgs::read_hardware_key_protector(vmgs)
1702            .await
1703            .is_err_and(|err| {
1704                matches!(
1705                    err,
1706                    vmgs::ReadFromVmgsError::EntryNotFound(FileId::HW_KEY_PROTECTOR)
1707                )
1708            })
1709    }
1710
1711    fn new_key_protector() -> KeyProtector {
1712        // Ingress and egress KPs are assumed to be the only two KPs, therefore `NUMBER_KP` should be 2
1713        assert_eq!(NUMBER_KP, 2);
1714
1715        let ingress_dek = DekKp {
1716            dek_buffer: [1; DEK_BUFFER_SIZE],
1717        };
1718        let egress_dek = DekKp {
1719            dek_buffer: [2; DEK_BUFFER_SIZE],
1720        };
1721        let ingress_gsp = GspKp {
1722            gsp_length: GSP_BUFFER_SIZE as u32,
1723            gsp_buffer: [3; GSP_BUFFER_SIZE],
1724        };
1725        let egress_gsp = GspKp {
1726            gsp_length: GSP_BUFFER_SIZE as u32,
1727            gsp_buffer: [4; GSP_BUFFER_SIZE],
1728        };
1729        KeyProtector {
1730            dek: [ingress_dek, egress_dek],
1731            gsp: [ingress_gsp, egress_gsp],
1732            active_kp: 0,
1733        }
1734    }
1735
1736    fn new_key_protector_by_id(
1737        id_guid: Option<Guid>,
1738        ported: Option<u8>,
1739        found_id: bool,
1740    ) -> KeyProtectorById {
1741        let key_protector_by_id = openhcl_attestation_protocol::vmgs::KeyProtectorById {
1742            id_guid: id_guid.unwrap_or_else(Guid::new_random),
1743            ported: ported.unwrap_or(0),
1744            pad: [0; 3],
1745        };
1746
1747        KeyProtectorById {
1748            inner: key_protector_by_id,
1749            found_id,
1750        }
1751    }
1752
1753    async fn new_test_get(
1754        spawn: impl Spawn,
1755        enable_igvm_attest: bool,
1756        plan: Option<IgvmAgentTestPlan>,
1757    ) -> TestGet {
1758        if enable_igvm_attest {
1759            const TEST_DEVICE_MEMORY_SIZE: u64 = 64;
1760            // Use `DeviceTestMemory` to set up shared memory required by the IGVM_ATTEST GET calls.
1761            let dev_test_mem = user_driver_emulated_mock::DeviceTestMemory::new(
1762                TEST_DEVICE_MEMORY_SIZE,
1763                true,
1764                "test-attest",
1765            );
1766
1767            let mut test_get = guest_emulation_transport::test_utilities::new_transport_pair(
1768                spawn,
1769                None,
1770                get_protocol::ProtocolVersion::NICKEL_REV2,
1771                Some(dev_test_mem.guest_memory()),
1772                plan,
1773            )
1774            .await;
1775
1776            test_get.client.set_gpa_allocator(dev_test_mem.dma_client());
1777
1778            test_get
1779        } else {
1780            guest_emulation_transport::test_utilities::new_transport_pair(
1781                spawn,
1782                None,
1783                get_protocol::ProtocolVersion::NICKEL_REV2,
1784                None,
1785                None,
1786            )
1787            .await
1788        }
1789    }
1790
1791    #[async_test]
1792    async fn do_nothing_without_derived_keys() {
1793        let mut vmgs = new_formatted_vmgs().await;
1794
1795        let mut key_protector = new_key_protector();
1796        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
1797
1798        let key_protector_settings = KeyProtectorSettings {
1799            should_write_kp: false,
1800            use_gsp_by_id: false,
1801            use_hardware_unlock: false,
1802            decrypt_gsp_type: GspType::None,
1803            encrypt_gsp_type: GspType::None,
1804        };
1805
1806        let bios_guid = Guid::new_random();
1807
1808        unlock_vmgs_data_store(
1809            &mut vmgs,
1810            false,
1811            &mut key_protector,
1812            &mut key_protector_by_id,
1813            None,
1814            key_protector_settings,
1815            bios_guid,
1816        )
1817        .await
1818        .unwrap();
1819
1820        assert!(key_protector_is_empty(&mut vmgs).await);
1821        assert!(key_protector_by_id_is_empty(&mut vmgs).await);
1822
1823        // Create another instance as the previous `unlock_vmgs_data_store` took ownership of the last one
1824        let key_protector_settings = KeyProtectorSettings {
1825            should_write_kp: false,
1826            use_gsp_by_id: false,
1827            use_hardware_unlock: false,
1828            decrypt_gsp_type: GspType::None,
1829            encrypt_gsp_type: GspType::None,
1830        };
1831
1832        // Even if the VMGS is encrypted, if no derived keys are provided, nothing should happen
1833        unlock_vmgs_data_store(
1834            &mut vmgs,
1835            true,
1836            &mut key_protector,
1837            &mut key_protector_by_id,
1838            None,
1839            key_protector_settings,
1840            bios_guid,
1841        )
1842        .await
1843        .unwrap();
1844
1845        assert!(key_protector_is_empty(&mut vmgs).await);
1846        assert!(key_protector_by_id_is_empty(&mut vmgs).await);
1847    }
1848
1849    #[async_test]
1850    async fn provision_vmgs_and_rotate_keys() {
1851        let mut vmgs = new_formatted_vmgs().await;
1852
1853        let mut key_protector = new_key_protector();
1854        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
1855
1856        let ingress = [1; AES_GCM_KEY_LENGTH];
1857        let egress = [2; AES_GCM_KEY_LENGTH];
1858        let derived_keys = Keys {
1859            ingress,
1860            decrypt_egress: None,
1861            encrypt_egress: egress,
1862        };
1863
1864        let key_protector_settings = KeyProtectorSettings {
1865            should_write_kp: true,
1866            use_gsp_by_id: true,
1867            use_hardware_unlock: false,
1868            decrypt_gsp_type: GspType::GspById,
1869            encrypt_gsp_type: GspType::GspById,
1870        };
1871
1872        let bios_guid = Guid::new_random();
1873
1874        // Without encryption implies the provision path
1875        // The VMGS will be locked using the egress key
1876        unlock_vmgs_data_store(
1877            &mut vmgs,
1878            false,
1879            &mut key_protector,
1880            &mut key_protector_by_id,
1881            Some(derived_keys),
1882            key_protector_settings,
1883            bios_guid,
1884        )
1885        .await
1886        .unwrap();
1887
1888        // The ingress key is essentially ignored since the VMGS wasn't previously encrypted
1889        vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
1890
1891        // The egress key was used to lock the VMGS after provisioning
1892        vmgs.unlock_with_encryption_key(&egress).await.unwrap();
1893        // Since this is a new VMGS, the egress key is the first and only key
1894        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(0));
1895
1896        // Since both `should_write_kp` and `use_gsp_by_id` are true, both key protectors should be updated
1897        assert!(!key_protector_is_empty(&mut vmgs).await);
1898        assert!(!key_protector_by_id_is_empty(&mut vmgs).await);
1899
1900        let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
1901            .await
1902            .unwrap();
1903        assert_eq!(found_key_protector.as_bytes(), key_protector.as_bytes());
1904
1905        let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
1906        assert_eq!(
1907            found_key_protector_by_id.as_bytes(),
1908            key_protector_by_id.inner.as_bytes()
1909        );
1910
1911        // Now that the VMGS has been provisioned, simulate the rotation of keys
1912        let new_egress = [3; AES_GCM_KEY_LENGTH];
1913
1914        let mut new_key_protector = new_key_protector();
1915        let mut new_key_protector_by_id = new_key_protector_by_id(None, None, false);
1916
1917        let key_protector_settings = KeyProtectorSettings {
1918            should_write_kp: true,
1919            use_gsp_by_id: true,
1920            use_hardware_unlock: false,
1921            decrypt_gsp_type: GspType::GspById,
1922            encrypt_gsp_type: GspType::GspById,
1923        };
1924
1925        // Ingress is now the old egress, and we provide a new new egress key
1926        let derived_keys = Keys {
1927            ingress: egress,
1928            decrypt_egress: None,
1929            encrypt_egress: new_egress,
1930        };
1931
1932        unlock_vmgs_data_store(
1933            &mut vmgs,
1934            true,
1935            &mut new_key_protector,
1936            &mut new_key_protector_by_id,
1937            Some(derived_keys),
1938            key_protector_settings,
1939            bios_guid,
1940        )
1941        .await
1942        .unwrap();
1943
1944        // We should still fail to unlock the VMGS with the original ingress key
1945        vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
1946        // The old egress key should no longer be able to unlock the VMGS
1947        vmgs.unlock_with_encryption_key(&egress).await.unwrap_err();
1948
1949        // The new egress key should be able to unlock the VMGS
1950        vmgs.unlock_with_encryption_key(&new_egress).await.unwrap();
1951        // The old egress key was removed, but not before the new egress key was added in the 1th slot
1952        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
1953
1954        let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
1955            .await
1956            .unwrap();
1957        assert_eq!(found_key_protector.as_bytes(), new_key_protector.as_bytes());
1958
1959        let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
1960        assert_eq!(
1961            found_key_protector_by_id.as_bytes(),
1962            new_key_protector_by_id.inner.as_bytes()
1963        );
1964    }
1965
1966    #[async_test]
1967    async fn unlock_previously_encrypted_vmgs_with_ingress_key() {
1968        let mut vmgs = new_formatted_vmgs().await;
1969
1970        let mut key_protector = new_key_protector();
1971        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
1972
1973        let ingress = [1; AES_GCM_KEY_LENGTH];
1974        let egress = [2; AES_GCM_KEY_LENGTH];
1975
1976        let derived_keys = Keys {
1977            ingress,
1978            decrypt_egress: None,
1979            encrypt_egress: egress,
1980        };
1981
1982        vmgs.update_encryption_key(&ingress, EncryptionAlgorithm::AES_GCM)
1983            .await
1984            .unwrap();
1985
1986        // Initially, the VMGS can be unlocked using the ingress key
1987        vmgs.unlock_with_encryption_key(&ingress).await.unwrap();
1988        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(0));
1989
1990        let key_protector_settings = KeyProtectorSettings {
1991            should_write_kp: true,
1992            use_gsp_by_id: true,
1993            use_hardware_unlock: false,
1994            decrypt_gsp_type: GspType::GspById,
1995            encrypt_gsp_type: GspType::GspById,
1996        };
1997
1998        let bios_guid = Guid::new_random();
1999
2000        unlock_vmgs_data_store(
2001            &mut vmgs,
2002            true,
2003            &mut key_protector,
2004            &mut key_protector_by_id,
2005            Some(derived_keys),
2006            key_protector_settings,
2007            bios_guid,
2008        )
2009        .await
2010        .unwrap();
2011
2012        // After the VMGS has been unlocked, the VMGS encryption key should be rotated from ingress to egress
2013        vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
2014        vmgs.unlock_with_encryption_key(&egress).await.unwrap();
2015        // The ingress key was removed, but not before the egress key was added in the 0th slot
2016        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2017
2018        // Since both `should_write_kp` and `use_gsp_by_id` are true, both key protectors should be updated
2019        let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
2020            .await
2021            .unwrap();
2022        assert_eq!(found_key_protector.as_bytes(), key_protector.as_bytes());
2023
2024        let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
2025        assert_eq!(
2026            found_key_protector_by_id.as_bytes(),
2027            key_protector_by_id.inner.as_bytes()
2028        );
2029    }
2030
2031    #[async_test]
2032    async fn failed_to_persist_ingress_key_so_use_egress_key_to_unlock_vmgs() {
2033        let mut vmgs = new_formatted_vmgs().await;
2034
2035        let mut key_protector = new_key_protector();
2036        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2037
2038        let ingress = [1; AES_GCM_KEY_LENGTH];
2039        let decrypt_egress = [2; AES_GCM_KEY_LENGTH];
2040        let encrypt_egress = [3; AES_GCM_KEY_LENGTH];
2041
2042        let derived_keys = Keys {
2043            ingress,
2044            decrypt_egress: Some(decrypt_egress),
2045            encrypt_egress,
2046        };
2047
2048        // Add only the egress key to the VMGS to simulate a failure to persist the ingress key
2049        vmgs.test_add_new_encryption_key(&decrypt_egress, EncryptionAlgorithm::AES_GCM)
2050            .await
2051            .unwrap();
2052        let egress_key_index = vmgs.test_get_active_datastore_key_index().unwrap();
2053        assert_eq!(egress_key_index, 0);
2054
2055        vmgs.unlock_with_encryption_key(&decrypt_egress)
2056            .await
2057            .unwrap();
2058        let found_egress_key_index = vmgs.test_get_active_datastore_key_index().unwrap();
2059        assert_eq!(found_egress_key_index, egress_key_index);
2060
2061        // Confirm that the ingress key cannot be used to unlock the VMGS
2062        vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
2063
2064        let key_protector_settings = KeyProtectorSettings {
2065            should_write_kp: true,
2066            use_gsp_by_id: true,
2067            use_hardware_unlock: false,
2068            decrypt_gsp_type: GspType::GspById,
2069            encrypt_gsp_type: GspType::GspById,
2070        };
2071
2072        let bios_guid = Guid::new_random();
2073
2074        unlock_vmgs_data_store(
2075            &mut vmgs,
2076            true,
2077            &mut key_protector,
2078            &mut key_protector_by_id,
2079            Some(derived_keys),
2080            key_protector_settings,
2081            bios_guid,
2082        )
2083        .await
2084        .unwrap();
2085
2086        // Confirm that the ingress key was not added
2087        vmgs.unlock_with_encryption_key(&ingress).await.unwrap_err();
2088
2089        // Confirm that the decrypt egress key no longer works
2090        vmgs.unlock_with_encryption_key(&decrypt_egress)
2091            .await
2092            .unwrap_err();
2093
2094        // The encrypt_egress key can unlock the VMGS and was added as a new key
2095        vmgs.unlock_with_encryption_key(&encrypt_egress)
2096            .await
2097            .unwrap();
2098        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2099
2100        // Since both `should_write_kp` and `use_gsp_by_id` are true, both key protectors should be updated
2101        let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
2102            .await
2103            .unwrap();
2104        assert_eq!(found_key_protector.as_bytes(), key_protector.as_bytes());
2105
2106        let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
2107        assert_eq!(
2108            found_key_protector_by_id.as_bytes(),
2109            key_protector_by_id.inner.as_bytes()
2110        );
2111    }
2112
2113    #[async_test]
2114    async fn fail_to_unlock_vmgs_with_existing_ingress_key() {
2115        let mut vmgs = new_formatted_vmgs().await;
2116
2117        let mut key_protector = new_key_protector();
2118        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2119
2120        let ingress = [1; AES_GCM_KEY_LENGTH];
2121
2122        // Ingress and egress keys are the same
2123        let derived_keys = Keys {
2124            ingress,
2125            decrypt_egress: None,
2126            encrypt_egress: ingress,
2127        };
2128
2129        // Add two random keys to the VMGS to simulate unlock failure when ingress and egress keys are the same
2130        let additional_key = [2; AES_GCM_KEY_LENGTH];
2131        let yet_another_key = [3; AES_GCM_KEY_LENGTH];
2132
2133        vmgs.test_add_new_encryption_key(&additional_key, EncryptionAlgorithm::AES_GCM)
2134            .await
2135            .unwrap();
2136        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(0));
2137
2138        vmgs.test_add_new_encryption_key(&yet_another_key, EncryptionAlgorithm::AES_GCM)
2139            .await
2140            .unwrap();
2141        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2142
2143        let key_protector_settings = KeyProtectorSettings {
2144            should_write_kp: true,
2145            use_gsp_by_id: true,
2146            use_hardware_unlock: false,
2147            decrypt_gsp_type: GspType::GspById,
2148            encrypt_gsp_type: GspType::GspById,
2149        };
2150
2151        let bios_guid = Guid::new_random();
2152
2153        let unlock_result = unlock_vmgs_data_store(
2154            &mut vmgs,
2155            true,
2156            &mut key_protector,
2157            &mut key_protector_by_id,
2158            Some(derived_keys),
2159            key_protector_settings,
2160            bios_guid,
2161        )
2162        .await;
2163        assert!(unlock_result.is_err());
2164        assert_eq!(
2165            unlock_result.unwrap_err().to_string(),
2166            "failed to unlock vmgs with the existing ingress key".to_string()
2167        );
2168    }
2169
2170    #[async_test]
2171    async fn fail_to_unlock_vmgs_with_new_ingress_key() {
2172        let mut vmgs = new_formatted_vmgs().await;
2173
2174        let mut key_protector = new_key_protector();
2175        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2176
2177        let derived_keys = Keys {
2178            ingress: [1; AES_GCM_KEY_LENGTH],
2179            decrypt_egress: None,
2180            encrypt_egress: [2; AES_GCM_KEY_LENGTH],
2181        };
2182
2183        // Add two random keys to the VMGS to simulate unlock failure when ingress and egress keys are *not* the same
2184        let additional_key = [3; AES_GCM_KEY_LENGTH];
2185        let yet_another_key = [4; AES_GCM_KEY_LENGTH];
2186
2187        vmgs.test_add_new_encryption_key(&additional_key, EncryptionAlgorithm::AES_GCM)
2188            .await
2189            .unwrap();
2190        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(0));
2191
2192        vmgs.test_add_new_encryption_key(&yet_another_key, EncryptionAlgorithm::AES_GCM)
2193            .await
2194            .unwrap();
2195        assert_eq!(vmgs.test_get_active_datastore_key_index(), Some(1));
2196
2197        let key_protector_settings = KeyProtectorSettings {
2198            should_write_kp: true,
2199            use_gsp_by_id: true,
2200            use_hardware_unlock: false,
2201            decrypt_gsp_type: GspType::GspById,
2202            encrypt_gsp_type: GspType::GspById,
2203        };
2204
2205        let bios_guid = Guid::new_random();
2206
2207        let unlock_result = unlock_vmgs_data_store(
2208            &mut vmgs,
2209            true,
2210            &mut key_protector,
2211            &mut key_protector_by_id,
2212            Some(derived_keys),
2213            key_protector_settings,
2214            bios_guid,
2215        )
2216        .await;
2217        assert!(unlock_result.is_err());
2218        assert_eq!(
2219            unlock_result.unwrap_err().to_string(),
2220            "failed to unlock vmgs with the existing ingress key".to_string()
2221        );
2222    }
2223
2224    #[async_test]
2225    async fn get_derived_keys_using_id() {
2226        let bios_guid = Guid::new_random();
2227
2228        let gsp_response_by_id = GuestStateProtectionById {
2229            seed: guest_emulation_transport::api::GspCleartextContent {
2230                length: GSP_CLEARTEXT_MAX,
2231                buffer: [1; GSP_CLEARTEXT_MAX as usize * 2],
2232            },
2233            extended_status_flags: GspExtendedStatusFlags::from_bits(0),
2234        };
2235
2236        // When the key protector by id inner `id_guid` is all zeroes, the derived ingress and egress keys
2237        // should be identical.
2238        let mut key_protector_by_id =
2239            new_key_protector_by_id(Some(Guid::new_zeroed()), None, false);
2240        let derived_keys =
2241            get_derived_keys_by_id(&mut key_protector_by_id, bios_guid, gsp_response_by_id)
2242                .unwrap();
2243
2244        assert_eq!(derived_keys.ingress, derived_keys.encrypt_egress);
2245
2246        // When the key protector by id inner `id_guid` is not all zeroes, the derived ingress and egress keys
2247        // should be different.
2248        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2249        let derived_keys =
2250            get_derived_keys_by_id(&mut key_protector_by_id, bios_guid, gsp_response_by_id)
2251                .unwrap();
2252
2253        assert_ne!(derived_keys.ingress, derived_keys.encrypt_egress);
2254
2255        // When the `gsp_response_by_id` seed length is 0, deriving a key will fail.
2256        let gsp_response_by_id_with_0_length_seed = GuestStateProtectionById {
2257            seed: guest_emulation_transport::api::GspCleartextContent {
2258                length: 0,
2259                buffer: [1; GSP_CLEARTEXT_MAX as usize * 2],
2260            },
2261            extended_status_flags: GspExtendedStatusFlags::from_bits(0),
2262        };
2263
2264        let derived_keys_response = get_derived_keys_by_id(
2265            &mut key_protector_by_id,
2266            bios_guid,
2267            gsp_response_by_id_with_0_length_seed,
2268        );
2269        assert!(derived_keys_response.is_err());
2270        assert_eq!(
2271            derived_keys_response.unwrap_err().to_string(),
2272            "failed to derive an egress key based on current vm bios guid".to_string()
2273        );
2274    }
2275
2276    #[async_test]
2277    async fn pass_through_persist_all_key_protectors() {
2278        let mut vmgs = new_formatted_vmgs().await;
2279        let mut key_protector = new_key_protector();
2280        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2281        let bios_guid = Guid::new_random();
2282
2283        // Copied/cloned bits used for comparison later
2284        let kp_copy = key_protector.as_bytes().to_vec();
2285        let active_kp_copy = key_protector.active_kp;
2286
2287        // When all key protector settings are true, no actions will be taken on the key protectors or VMGS
2288        let key_protector_settings = KeyProtectorSettings {
2289            should_write_kp: true,
2290            use_gsp_by_id: true,
2291            use_hardware_unlock: true,
2292            decrypt_gsp_type: GspType::GspById,
2293            encrypt_gsp_type: GspType::GspById,
2294        };
2295        persist_all_key_protectors(
2296            &mut vmgs,
2297            &mut key_protector,
2298            &mut key_protector_by_id,
2299            bios_guid,
2300            key_protector_settings,
2301        )
2302        .await
2303        .unwrap();
2304
2305        assert!(key_protector_is_empty(&mut vmgs).await);
2306        assert!(key_protector_by_id_is_empty(&mut vmgs).await);
2307
2308        // The key protector should remain unchanged
2309        assert_eq!(active_kp_copy, key_protector.active_kp);
2310        assert_eq!(kp_copy.as_slice(), key_protector.as_bytes());
2311    }
2312
2313    #[async_test]
2314    async fn persist_all_key_protectors_write_key_protector_by_id() {
2315        let mut vmgs = new_formatted_vmgs().await;
2316        let mut key_protector = new_key_protector();
2317        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2318        let bios_guid = Guid::new_random();
2319
2320        // Copied/cloned bits used for comparison later
2321        let kp_copy = key_protector.as_bytes().to_vec();
2322        let active_kp_copy = key_protector.active_kp;
2323
2324        // When `use_gsp_by_id` is true and `should_write_kp` is false, the key protector by id should be written to the VMGS
2325        let key_protector_settings = KeyProtectorSettings {
2326            should_write_kp: false,
2327            use_gsp_by_id: true,
2328            use_hardware_unlock: false,
2329            decrypt_gsp_type: GspType::GspById,
2330            encrypt_gsp_type: GspType::GspById,
2331        };
2332        persist_all_key_protectors(
2333            &mut vmgs,
2334            &mut key_protector,
2335            &mut key_protector_by_id,
2336            bios_guid,
2337            key_protector_settings,
2338        )
2339        .await
2340        .unwrap();
2341
2342        // The previously empty VMGS now holds the key protector by id but not the key protector
2343        assert!(key_protector_is_empty(&mut vmgs).await);
2344        assert!(!key_protector_by_id_is_empty(&mut vmgs).await);
2345
2346        let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
2347        assert_eq!(
2348            found_key_protector_by_id.as_bytes(),
2349            key_protector_by_id.inner.as_bytes()
2350        );
2351
2352        // The key protector should remain unchanged
2353        assert_eq!(kp_copy.as_slice(), key_protector.as_bytes());
2354        assert_eq!(active_kp_copy, key_protector.active_kp);
2355    }
2356
2357    #[async_test]
2358    async fn persist_all_key_protectors_remove_ingress_kp() {
2359        let mut vmgs = new_formatted_vmgs().await;
2360        let mut key_protector = new_key_protector();
2361        let mut key_protector_by_id = new_key_protector_by_id(None, None, false);
2362        let bios_guid = Guid::new_random();
2363
2364        // Copied active KP for later use
2365        let active_kp_copy = key_protector.active_kp;
2366
2367        // When `use_gsp_by_id` is false, `should_write_kp` is true, and `use_hardware_unlock` is false, the active key protector's
2368        // active kp's dek should be zeroed, the active kp's gsp length should be set to 0, and the active kp should be incremented
2369        let key_protector_settings = KeyProtectorSettings {
2370            should_write_kp: true,
2371            use_gsp_by_id: false,
2372            use_hardware_unlock: false,
2373            decrypt_gsp_type: GspType::None,
2374            encrypt_gsp_type: GspType::None,
2375        };
2376        persist_all_key_protectors(
2377            &mut vmgs,
2378            &mut key_protector,
2379            &mut key_protector_by_id,
2380            bios_guid,
2381            key_protector_settings,
2382        )
2383        .await
2384        .unwrap();
2385
2386        assert!(!key_protector_is_empty(&mut vmgs).await);
2387        assert!(key_protector_by_id_is_empty(&mut vmgs).await);
2388
2389        // The previously empty VMGS's key protector should now be overwritten
2390        let found_key_protector = vmgs::read_key_protector(&mut vmgs, AES_WRAPPED_AES_KEY_LENGTH)
2391            .await
2392            .unwrap();
2393
2394        assert!(
2395            found_key_protector.dek[active_kp_copy as usize]
2396                .dek_buffer
2397                .iter()
2398                .all(|&b| b == 0),
2399        );
2400        assert_eq!(
2401            found_key_protector.gsp[active_kp_copy as usize].gsp_length,
2402            0
2403        );
2404        assert_eq!(found_key_protector.active_kp, active_kp_copy + 1);
2405    }
2406
2407    #[async_test]
2408    async fn persist_all_key_protectors_mark_key_protector_by_id_as_not_in_use() {
2409        let mut vmgs = new_formatted_vmgs().await;
2410        let mut key_protector = new_key_protector();
2411        let mut key_protector_by_id = new_key_protector_by_id(None, None, true);
2412        let bios_guid = Guid::new_random();
2413
2414        // When `use_gsp_by_id` is false, `should_write_kp` is true, `use_hardware_unlock` is true, and
2415        // the key protector by id is found and not ported, the key protector by id should be marked as ported
2416        let key_protector_settings = KeyProtectorSettings {
2417            should_write_kp: true,
2418            use_gsp_by_id: false,
2419            use_hardware_unlock: true,
2420            decrypt_gsp_type: GspType::None,
2421            encrypt_gsp_type: GspType::None,
2422        };
2423
2424        persist_all_key_protectors(
2425            &mut vmgs,
2426            &mut key_protector,
2427            &mut key_protector_by_id,
2428            bios_guid,
2429            key_protector_settings,
2430        )
2431        .await
2432        .unwrap();
2433
2434        assert!(key_protector_is_empty(&mut vmgs).await);
2435        assert!(!key_protector_by_id_is_empty(&mut vmgs).await);
2436
2437        // The previously empty VMGS's key protector by id should now be overwritten
2438        let found_key_protector_by_id = vmgs::read_key_protector_by_id(&mut vmgs).await.unwrap();
2439        assert_eq!(found_key_protector_by_id.ported, 1);
2440        assert_eq!(
2441            found_key_protector_by_id.id_guid,
2442            key_protector_by_id.inner.id_guid
2443        );
2444    }
2445
2446    // --- initialize_platform_security tests ---
2447
2448    #[async_test]
2449    async fn init_sec_suppress_attestation(driver: DefaultDriver) {
2450        let mut vmgs = new_formatted_vmgs().await;
2451
2452        // Write non-zero agent data to VMGS so we can verify it is returned.
2453        let agent = SecurityProfile {
2454            agent_data: [0xAA; AGENT_DATA_MAX_SIZE],
2455        };
2456        vmgs.write_file(FileId::ATTEST, agent.as_bytes())
2457            .await
2458            .unwrap();
2459
2460        // Ensure no IGVM attest call out
2461        let get_pair = new_test_get(driver, false, None).await;
2462
2463        let bios_guid = Guid::new_random();
2464        let att_cfg = Default::default();
2465
2466        // Ensure VMGS is not encrypted and agent data is empty before the call
2467        assert!(!vmgs.encrypted());
2468
2469        // Obtain a LocalDriver briefly, then run the async flow under the pool executor
2470        let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
2471        let res = initialize_platform_security(
2472            &get_pair.client,
2473            bios_guid,
2474            &att_cfg,
2475            &mut vmgs,
2476            None, // no TEE when suppressed
2477            true, // suppress_attestation
2478            ldriver,
2479            GuestStateEncryptionPolicy::None,
2480            true,
2481        )
2482        .await
2483        .unwrap();
2484
2485        // VMGS remains unencrypted and KP/HWKP not written.
2486        assert!(!vmgs.encrypted());
2487        assert!(key_protector_is_empty(&mut vmgs).await);
2488        assert!(hardware_key_protector_is_empty(&mut vmgs).await);
2489        // Agent data passed through
2490        assert_eq!(res.agent_data.unwrap(), agent.agent_data.to_vec());
2491        // Secure key should be None without pre-provisioning
2492        assert!(res.guest_secret_key.is_none());
2493    }
2494
2495    #[async_test]
2496    async fn init_sec_secure_key_release_with_wrapped_key_request(driver: DefaultDriver) {
2497        let mut vmgs = new_formatted_vmgs().await;
2498
2499        // IGVM attest is required
2500        let get_pair = new_test_get(driver, true, None).await;
2501
2502        let bios_guid = Guid::new_random();
2503        let att_cfg = Default::default();
2504        let tee = MockTeeCall::new(0x1234);
2505
2506        // Ensure VMGS is not encrypted and agent data is empty before the call
2507        assert!(!vmgs.encrypted());
2508
2509        // Obtain a LocalDriver briefly, then run the async flow under the pool executor
2510        let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
2511        let res = initialize_platform_security(
2512            &get_pair.client,
2513            bios_guid,
2514            &att_cfg,
2515            &mut vmgs,
2516            Some(&tee),
2517            false,
2518            ldriver.clone(),
2519            GuestStateEncryptionPolicy::Auto,
2520            true,
2521        )
2522        .await
2523        .unwrap();
2524
2525        // VMGS is now encrypted and HWKP is updated.
2526        assert!(vmgs.encrypted());
2527        assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
2528
2529        // Agent data should be the same as `key_reference` in the WRAPPED_KEY response.
2530        // See vm/devices/get/guest_emulation_device/src/test_igvm_agent.rs for the expected response.
2531        let key_reference = serde_json::json!({
2532            "key_info": {
2533                "host": "name"
2534            },
2535            "attestation_info": {
2536                "host": "attestation_name"
2537            }
2538        });
2539        let key_reference = serde_json::to_string(&key_reference).unwrap();
2540        let key_reference = key_reference.as_bytes();
2541        let mut expected_agent_data = [0u8; AGENT_DATA_MAX_SIZE];
2542        expected_agent_data[..key_reference.len()].copy_from_slice(key_reference);
2543        assert_eq!(res.agent_data.unwrap(), expected_agent_data.to_vec());
2544        // Secure key should be None without pre-provisioning
2545        assert!(res.guest_secret_key.is_none());
2546
2547        // Second call: VMGS unlock via SKR should succeed
2548        initialize_platform_security(
2549            &get_pair.client,
2550            bios_guid,
2551            &att_cfg,
2552            &mut vmgs,
2553            Some(&tee),
2554            false,
2555            ldriver,
2556            GuestStateEncryptionPolicy::Auto,
2557            true,
2558        )
2559        .await
2560        .unwrap();
2561
2562        // VMGS should remain encrypted
2563        assert!(vmgs.encrypted());
2564    }
2565
2566    #[async_test]
2567    async fn init_sec_secure_key_release_without_wrapped_key_request(driver: DefaultDriver) {
2568        let mut vmgs = new_formatted_vmgs().await;
2569
2570        // Write non-zero agent data to workaround the WRAPPED_KEY_REQUEST requirement.
2571        let agent = SecurityProfile {
2572            agent_data: [0xAA; AGENT_DATA_MAX_SIZE],
2573        };
2574        vmgs.write_file(FileId::ATTEST, agent.as_bytes())
2575            .await
2576            .unwrap();
2577
2578        // Skip WRAPPED_KEY_REQUEST for both boots
2579        let mut plan = IgvmAgentTestPlan::default();
2580        plan.insert(
2581            IgvmAttestRequestType::WRAPPED_KEY_REQUEST,
2582            VecDeque::from([IgvmAgentAction::NoResponse, IgvmAgentAction::NoResponse]),
2583        );
2584
2585        // IGVM attest is required
2586        let get_pair = new_test_get(driver, true, Some(plan)).await;
2587
2588        let bios_guid = Guid::new_random();
2589        let att_cfg = Default::default();
2590        let tee = MockTeeCall::new(0x1234);
2591
2592        // Ensure VMGS is not encrypted and agent data is empty before the call
2593        assert!(!vmgs.encrypted());
2594
2595        // Obtain a LocalDriver briefly, then run the async flow under the pool executor
2596        let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
2597        let res = initialize_platform_security(
2598            &get_pair.client,
2599            bios_guid,
2600            &att_cfg,
2601            &mut vmgs,
2602            Some(&tee),
2603            false,
2604            ldriver.clone(),
2605            GuestStateEncryptionPolicy::Auto,
2606            true,
2607        )
2608        .await
2609        .unwrap();
2610
2611        // VMGS is now encrypted and HWKP is updated.
2612        assert!(vmgs.encrypted());
2613        assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
2614        // Agent data passed through
2615        assert_eq!(res.agent_data.clone().unwrap(), agent.agent_data.to_vec());
2616        // Secure key should be None without pre-provisioning
2617        assert!(res.guest_secret_key.is_none());
2618
2619        // Second call: VMGS unlock via SKR should succeed
2620        let res = initialize_platform_security(
2621            &get_pair.client,
2622            bios_guid,
2623            &att_cfg,
2624            &mut vmgs,
2625            Some(&tee),
2626            false,
2627            ldriver,
2628            GuestStateEncryptionPolicy::Auto,
2629            true,
2630        )
2631        .await
2632        .unwrap();
2633
2634        // VMGS should remain encrypted
2635        assert!(vmgs.encrypted());
2636        // Agent data passed through
2637        assert_eq!(res.agent_data.clone().unwrap(), agent.agent_data.to_vec());
2638        // Secure key should be None without pre-provisioning
2639        assert!(res.guest_secret_key.is_none());
2640    }
2641
2642    #[async_test]
2643    async fn init_sec_secure_key_release_hw_sealing_backup(driver: DefaultDriver) {
2644        let mut vmgs = new_formatted_vmgs().await;
2645
2646        // IGVM attest is required
2647        let mut plan = IgvmAgentTestPlan::default();
2648        plan.insert(
2649            IgvmAttestRequestType::WRAPPED_KEY_REQUEST,
2650            VecDeque::from([
2651                IgvmAgentAction::RespondSuccess,
2652                // initialize_platform_security will attempt SKR/unlock 10 times
2653                IgvmAgentAction::RespondFailure,
2654                IgvmAgentAction::RespondFailure,
2655                IgvmAgentAction::RespondFailure,
2656                IgvmAgentAction::RespondFailure,
2657                IgvmAgentAction::RespondFailure,
2658                IgvmAgentAction::RespondFailure,
2659                IgvmAgentAction::RespondFailure,
2660                IgvmAgentAction::RespondFailure,
2661                IgvmAgentAction::RespondFailure,
2662                IgvmAgentAction::RespondFailure,
2663            ]),
2664        );
2665
2666        let get_pair = new_test_get(driver, true, Some(plan)).await;
2667
2668        let bios_guid = Guid::new_random();
2669        let att_cfg = Default::default();
2670
2671        // Ensure VMGS is not encrypted and agent data is empty before the call
2672        assert!(!vmgs.encrypted());
2673
2674        // Obtain a LocalDriver briefly, then run the async flow under the pool executor
2675        let tee = MockTeeCall::new(0x1234);
2676        let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
2677        let res = initialize_platform_security(
2678            &get_pair.client,
2679            bios_guid,
2680            &att_cfg,
2681            &mut vmgs,
2682            Some(&tee),
2683            false,
2684            ldriver.clone(),
2685            GuestStateEncryptionPolicy::Auto,
2686            true,
2687        )
2688        .await
2689        .unwrap();
2690
2691        // VMGS is now encrypted and HWKP is updated.
2692        assert!(vmgs.encrypted());
2693        assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
2694        // Agent data should be the same as `key_reference` in the WRAPPED_KEY response.
2695        // See vm/devices/get/guest_emulation_device/src/test_igvm_agent.rs for the expected response.
2696        let key_reference = serde_json::json!({
2697            "key_info": {
2698                "host": "name"
2699            },
2700            "attestation_info": {
2701                "host": "attestation_name"
2702            }
2703        });
2704        let key_reference = serde_json::to_string(&key_reference).unwrap();
2705        let key_reference = key_reference.as_bytes();
2706        let mut expected_agent_data = [0u8; AGENT_DATA_MAX_SIZE];
2707        expected_agent_data[..key_reference.len()].copy_from_slice(key_reference);
2708        assert_eq!(res.agent_data.unwrap(), expected_agent_data.to_vec());
2709        // Secure key should be None without pre-provisioning
2710        assert!(res.guest_secret_key.is_none());
2711
2712        // Second call: VMGS unlock via key recovered with hardware sealing
2713        // NOTE: The test relies on the test GED to return failing WRAPPED_KEY response
2714        // with retry recommendation as false to skip the retry loop in
2715        // secure_key_release::request_vmgs_encryption_keys. Otherwise, the test will stuck
2716        // on the timer.sleep() as the the driver is not progressed.
2717        initialize_platform_security(
2718            &get_pair.client,
2719            bios_guid,
2720            &att_cfg,
2721            &mut vmgs,
2722            Some(&tee),
2723            false,
2724            ldriver,
2725            GuestStateEncryptionPolicy::Auto,
2726            true,
2727        )
2728        .await
2729        .unwrap();
2730
2731        // VMGS should remain encrypted
2732        assert!(vmgs.encrypted());
2733    }
2734
2735    #[async_test]
2736    async fn init_sec_secure_key_release_skip_hw_unsealing(driver: DefaultDriver) {
2737        let mut vmgs = new_formatted_vmgs().await;
2738
2739        // IGVM attest is required
2740        // KEY_RELEASE succeeds on first boot, fails with skip_hw_unsealing on second boot.
2741        // WRAPPED_KEY is not in the plan, so it falls back to default (success) every time.
2742        let mut plan = IgvmAgentTestPlan::default();
2743        plan.insert(
2744            IgvmAttestRequestType::KEY_RELEASE_REQUEST,
2745            VecDeque::from([
2746                IgvmAgentAction::RespondSuccess,
2747                IgvmAgentAction::RespondFailureSkipHwUnsealing,
2748            ]),
2749        );
2750
2751        let get_pair = new_test_get(driver, true, Some(plan)).await;
2752
2753        let bios_guid = Guid::new_random();
2754        let att_cfg = Default::default();
2755
2756        // Ensure VMGS is not encrypted and agent data is empty before the call
2757        assert!(!vmgs.encrypted());
2758
2759        // Obtain a LocalDriver briefly, then run the async flow under the pool executor
2760        let tee = MockTeeCall::new(0x1234);
2761        let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
2762        let res = initialize_platform_security(
2763            &get_pair.client,
2764            bios_guid,
2765            &att_cfg,
2766            &mut vmgs,
2767            Some(&tee),
2768            false,
2769            ldriver.clone(),
2770            GuestStateEncryptionPolicy::Auto,
2771            true,
2772        )
2773        .await
2774        .unwrap();
2775
2776        // VMGS is now encrypted and HWKP is updated.
2777        assert!(vmgs.encrypted());
2778        assert!(!hardware_key_protector_is_empty(&mut vmgs).await);
2779        // Agent data should be the same as `key_reference` in the WRAPPED_KEY response.
2780        let key_reference = serde_json::json!({
2781            "key_info": {
2782                "host": "name"
2783            },
2784            "attestation_info": {
2785                "host": "attestation_name"
2786            }
2787        });
2788        let key_reference = serde_json::to_string(&key_reference).unwrap();
2789        let key_reference = key_reference.as_bytes();
2790        let mut expected_agent_data = [0u8; AGENT_DATA_MAX_SIZE];
2791        expected_agent_data[..key_reference.len()].copy_from_slice(key_reference);
2792        assert_eq!(res.agent_data.unwrap(), expected_agent_data.to_vec());
2793        // Secure key should be None without pre-provisioning
2794        assert!(res.guest_secret_key.is_none());
2795
2796        // Second call: KEY_RELEASE fails with skip_hw_unsealing signal.
2797        // The skip_hw_unsealing signal causes the hardware unsealing fallback to be
2798        // skipped, so VMGS unlock should fail.
2799        // NOTE: The test relies on the test GED to return failing KEY_RELEASE response
2800        // with retry recommendation as false so the retry loop terminates immediately.
2801        // Otherwise, the test will get stuck on timer.sleep() as the driver is not
2802        // progressed.
2803        let result = initialize_platform_security(
2804            &get_pair.client,
2805            bios_guid,
2806            &att_cfg,
2807            &mut vmgs,
2808            Some(&tee),
2809            false,
2810            ldriver,
2811            GuestStateEncryptionPolicy::Auto,
2812            true,
2813        )
2814        .await;
2815
2816        assert!(result.is_err());
2817    }
2818
2819    #[async_test]
2820    async fn init_sec_secure_key_release_no_hw_sealing_backup(driver: DefaultDriver) {
2821        let mut vmgs = new_formatted_vmgs().await;
2822
2823        // IGVM attest is required
2824        let mut plan = IgvmAgentTestPlan::default();
2825        plan.insert(
2826            IgvmAttestRequestType::WRAPPED_KEY_REQUEST,
2827            VecDeque::from([
2828                IgvmAgentAction::RespondSuccess,
2829                // initialize_platform_security will attempt SKR/unlock 10 times
2830                IgvmAgentAction::RespondFailure,
2831                IgvmAgentAction::RespondFailure,
2832                IgvmAgentAction::RespondFailure,
2833                IgvmAgentAction::RespondFailure,
2834                IgvmAgentAction::RespondFailure,
2835                IgvmAgentAction::RespondFailure,
2836                IgvmAgentAction::RespondFailure,
2837                IgvmAgentAction::RespondFailure,
2838                IgvmAgentAction::RespondFailure,
2839                IgvmAgentAction::RespondFailure,
2840            ]),
2841        );
2842
2843        let get_pair = new_test_get(driver, true, Some(plan)).await;
2844
2845        let bios_guid = Guid::new_random();
2846        let att_cfg = Default::default();
2847        // Without hardware sealing support
2848        let tee = MockTeeCallNoGetDerivedKey {};
2849
2850        // Ensure VMGS is not encrypted and agent data is empty before the call
2851        assert!(!vmgs.encrypted());
2852
2853        // Obtain a LocalDriver briefly, then run the async flow under the pool executor
2854        let ldriver = pal_async::local::block_with_io(|ld| async move { ld });
2855        let res = initialize_platform_security(
2856            &get_pair.client,
2857            bios_guid,
2858            &att_cfg,
2859            &mut vmgs,
2860            Some(&tee),
2861            false,
2862            ldriver.clone(),
2863            GuestStateEncryptionPolicy::Auto,
2864            true,
2865        )
2866        .await
2867        .unwrap();
2868
2869        // VMGS is now encrypted but HWKP remains empty.
2870        assert!(vmgs.encrypted());
2871        assert!(hardware_key_protector_is_empty(&mut vmgs).await);
2872        // Agent data should be the same as `key_reference` in the WRAPPED_KEY response.
2873        // See vm/devices/get/guest_emulation_device/src/test_igvm_agent.rs for the expected response.
2874        let key_reference = serde_json::json!({
2875            "key_info": {
2876                "host": "name"
2877            },
2878            "attestation_info": {
2879                "host": "attestation_name"
2880            }
2881        });
2882        let key_reference = serde_json::to_string(&key_reference).unwrap();
2883        let key_reference = key_reference.as_bytes();
2884        let mut expected_agent_data = [0u8; AGENT_DATA_MAX_SIZE];
2885        expected_agent_data[..key_reference.len()].copy_from_slice(key_reference);
2886        assert_eq!(res.agent_data.unwrap(), expected_agent_data.to_vec());
2887        // Secure key should be None without pre-provisioning
2888        assert!(res.guest_secret_key.is_none());
2889
2890        // Second call: VMGS unlock should fail without hardware sealing support
2891        let result = initialize_platform_security(
2892            &get_pair.client,
2893            bios_guid,
2894            &att_cfg,
2895            &mut vmgs,
2896            Some(&tee),
2897            false,
2898            ldriver,
2899            GuestStateEncryptionPolicy::Auto,
2900            true,
2901        )
2902        .await;
2903
2904        assert!(result.is_err());
2905    }
2906
2907    #[test]
2908    fn test_get_provenance_claims() {
2909        // Test JWT: not a valid credential or secret for anything.
2910        const PROVENANCE_DOC: &str = include_str!("../test_data/valid_jwt");
2911        let doc = PROVENANCE_DOC.trim().strip_prefix("placeholder_").unwrap();
2912        let claims = get_provenance_claims(doc.as_bytes()).unwrap();
2913        assert_eq!(
2914            claims.id,
2915            guid::guid!("03020100-0504-0706-0809-0a0b0c0d0e0f")
2916        );
2917        assert_eq!(
2918            claims.signer,
2919            "did:x509:0:sha256:ea76599d86897382aa519ff2bc0fa6b9c15d60da2ebe53e72139cd317b0797ed:subject:fican.cvmprovisioningservice.core.azure-test.net"
2920        );
2921    }
2922
2923    #[test]
2924    fn test_derive_vmgsid() {
2925        const SEED_DOC_1: &str = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F,4C6162656C5F435053,436F6E746578745F564D4753,32";
2926        const SEED_DOC_2: &str = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F,4C6162656C5F435053,436F6E746578745F564D4753";
2927        const SEED_DOC_3: &str = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F,4C6162656C5F435053,436F6E746578745F564D4753,32,ABCDEF";
2928        const GUID: Guid = guid::guid!("b0587f2d-11e6-9f66-1af4-8b4a619147c8");
2929
2930        let vmgsid1 = derive_vmgsid(SEED_DOC_1.as_bytes()).unwrap();
2931        assert_eq!(vmgsid1, GUID);
2932
2933        let vmgsid2 = derive_vmgsid(SEED_DOC_2.as_bytes()).unwrap();
2934        assert_eq!(vmgsid2, GUID);
2935
2936        let vmgsid3 = derive_vmgsid(SEED_DOC_3.as_bytes()).unwrap();
2937        assert_eq!(vmgsid3, GUID);
2938    }
2939}