Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2680,6 +2680,7 @@ version = "0.0.0"
dependencies = [
"anyhow",
"chipset_resources",
"cvm_tracing",
"futures",
"futures-concurrency",
"get_protocol",
Expand Down Expand Up @@ -7438,18 +7439,21 @@ name = "tpm"
version = "0.0.0"
dependencies = [
"async-trait",
"base64 0.22.1",
"bitfield-struct 0.11.0",
"chipset_device",
"chipset_device_resources",
"cvm_tracing",
"getrandom 0.3.3",
"guestmem",
"guid",
"inspect",
"mesh",
"ms-tpm-20-ref",
"open_enum",
"pal_async",
"parking_lot",
"sha2",
"thiserror 2.0.16",
"tpm_resources",
"tracelimit",
Expand All @@ -7463,6 +7467,7 @@ dependencies = [
name = "tpm_resources"
version = "0.0.0"
dependencies = [
"guid",
"inspect",
"mesh",
"vm_resource",
Expand Down
105 changes: 102 additions & 3 deletions openhcl/underhill_attestation/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub use igvm_attest::IgvmAttestRequestHelper;
pub use igvm_attest::ak_cert::parse_response as parse_ak_cert_response;

use ::vmgs::EncryptionAlgorithm;
use ::vmgs::GspType;
use ::vmgs::Vmgs;
use cvm_tracing::CVM_ALLOWED;
use get_protocol::dps_json::GuestStateEncryptionPolicy;
Expand Down Expand Up @@ -155,6 +156,14 @@ enum PersistAllKeyProtectorsError {
WriteKeyProtectorById(#[source] vmgs::WriteToVmgsError),
}

// Operation types for provisioning telemetry.
#[derive(Debug)]
enum LogOpType {
BeginDecryptVmgs,
DecryptVmgs,
ConvertEncryptionType,
}

/// Label used by `derive_key`
const VMGS_KEY_DERIVE_LABEL: &[u8; 7] = b"VMGSKEY";

Expand All @@ -166,13 +175,18 @@ struct Keys {
}

/// Key protector settings
#[derive(Clone, Copy)]
struct KeyProtectorSettings {
/// Whether to update key protector
should_write_kp: bool,
/// Whether GSP by id is used
use_gsp_by_id: bool,
/// Whether hardware key sealing is used
use_hardware_unlock: bool,
/// GSP type used for decryption (for logging)
decrypt_gsp_type: GspType,
/// GSP type used for encryption (for logging)
encrypt_gsp_type: GspType,
}

/// Helper struct for [`protocol::vmgs::KeyProtectorById`]
Expand Down Expand Up @@ -362,7 +376,14 @@ pub async fn initialize_platform_security(

let vmgs_encrypted: bool = vmgs.is_encrypted();

tracing::info!(tcb_version=?tcb_version, vmgs_encrypted = vmgs_encrypted, "Deriving keys");
let start_time = std::time::SystemTime::now();
tracing::info!(
?tcb_version,
vmgs_encrypted,
op_type = ?LogOpType::BeginDecryptVmgs,
"Deriving keys"
);

let derived_keys_result = get_derived_keys(
get,
tee_call,
Expand All @@ -379,7 +400,19 @@ pub async fn initialize_platform_security(
strict_encryption_policy,
)
.await
.map_err(AttestationErrorInner::GetDerivedKeys)?;
.map_err(|e| {
tracing::error!(
CVM_ALLOWED,
op_type = ?LogOpType::DecryptVmgs,
success = false,
err = &e as &dyn std::error::Error,
latency = std::time::SystemTime::now()
.duration_since(start_time)
.map_or(0, |d| d.as_millis()),
"Failed to derive keys"
);
AttestationErrorInner::GetDerivedKeys(e)
})?;

// All Underhill VMs use VMGS encryption
tracing::info!("Unlocking VMGS");
Expand All @@ -394,12 +427,36 @@ pub async fn initialize_platform_security(
)
.await
{
tracing::error!(
CVM_ALLOWED,
op_type = ?LogOpType::DecryptVmgs,
success = false,
err = &e as &dyn std::error::Error,
latency = std::time::SystemTime::now()
.duration_since(start_time)
.map_or(0, |d| d.as_millis()),
"Failed to unlock datastore"
);
get.event_log_fatal(guest_emulation_transport::api::EventLogId::ATTESTATION_FAILED)
.await;

Err(AttestationErrorInner::UnlockVmgsDataStore(e))?
}

tracing::info!(
CVM_ALLOWED,
op_type = ?LogOpType::DecryptVmgs,
success = true,
decrypt_gsp_type = ?derived_keys_result
.key_protector_settings
.decrypt_gsp_type,
encrypt_gsp_type = ?derived_keys_result
.key_protector_settings
.encrypt_gsp_type,
latency = std::time::SystemTime::now().duration_since(start_time).map_or(0, |d| d.as_millis()),
"Unlocked datastore"
);

let state_refresh_request_from_gsp = derived_keys_result
.gsp_extended_status_flags
.state_refresh_request();
Expand Down Expand Up @@ -583,6 +640,8 @@ async fn get_derived_keys(
should_write_kp: true,
use_gsp_by_id: false,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::None,
encrypt_gsp_type: GspType::None,
};

let mut derived_keys = Keys {
Expand Down Expand Up @@ -908,6 +967,8 @@ async fn get_derived_keys(
// Not required for Id protection
key_protector_settings.should_write_kp = false;
key_protector_settings.use_gsp_by_id = true;
key_protector_settings.decrypt_gsp_type = GspType::GspById;
key_protector_settings.encrypt_gsp_type = GspType::GspById;

return Ok(DerivedKeyResult {
derived_keys: Some(derived_keys_by_id),
Expand All @@ -918,7 +979,11 @@ async fn get_derived_keys(

derived_keys.ingress = derived_keys_by_id.ingress;

tracing::info!(CVM_ALLOWED, "Converting GSP method.");
tracing::info!(
CVM_ALLOWED,
op_type = ?LogOpType::ConvertEncryptionType,
"Converting GSP method."
);
}

let egress_seed;
Expand All @@ -938,19 +1003,24 @@ async fn get_derived_keys(
gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize]
.to_vec(),
);
key_protector_settings.decrypt_gsp_type = GspType::GspById;
} else {
derived_keys.ingress = ingress_key;
}
} else {
key_protector_settings.decrypt_gsp_type = GspType::GspById;
}

// Choose best available egress seed
if no_gsp {
egress_seed =
gsp_response_by_id.seed.buffer[..gsp_response_by_id.seed.length as usize].to_vec();
key_protector_settings.use_gsp_by_id = true;
key_protector_settings.encrypt_gsp_type = GspType::GspById;
} else {
egress_seed =
gsp_response.new_gsp.buffer[..gsp_response.new_gsp.length as usize].to_vec();
key_protector_settings.encrypt_gsp_type = GspType::GspKey;
}
} else {
// `no_gsp` is false, using `gsp_response`
Expand All @@ -970,6 +1040,8 @@ async fn get_derived_keys(
if !no_kek {
derived_keys.ingress = ingress_key;
}

key_protector_settings.encrypt_gsp_type = GspType::GspKey;
} else {
tracing::info!(CVM_ALLOWED, "Using existing GSP.");

Expand All @@ -994,6 +1066,9 @@ async fn get_derived_keys(
key_protector_settings.should_write_kp = false;
decrypt_egress_key = Some(encrypt_egress_key);
}

key_protector_settings.decrypt_gsp_type = GspType::GspKey;
key_protector_settings.encrypt_gsp_type = GspType::GspKey;
}
}

Expand Down Expand Up @@ -1465,6 +1540,8 @@ mod tests {
should_write_kp: false,
use_gsp_by_id: false,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::None,
encrypt_gsp_type: GspType::None,
};

let bios_guid = Guid::new_random();
Expand All @@ -1489,6 +1566,8 @@ mod tests {
should_write_kp: false,
use_gsp_by_id: false,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::None,
encrypt_gsp_type: GspType::None,
};

// Even if the VMGS is encrypted, if no derived keys are provided, nothing should happen
Expand Down Expand Up @@ -1527,6 +1606,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: true,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::GspById,
encrypt_gsp_type: GspType::GspById,
};

let bios_guid = Guid::new_random();
Expand Down Expand Up @@ -1578,6 +1659,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: true,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::GspById,
encrypt_gsp_type: GspType::GspById,
};

// Ingress is now the old egress, and we provide a new new egress key
Expand Down Expand Up @@ -1649,6 +1732,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: true,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::GspById,
encrypt_gsp_type: GspType::GspById,
};

let bios_guid = Guid::new_random();
Expand Down Expand Up @@ -1721,6 +1806,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: true,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::GspById,
encrypt_gsp_type: GspType::GspById,
};

let bios_guid = Guid::new_random();
Expand Down Expand Up @@ -1798,6 +1885,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: true,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::GspById,
encrypt_gsp_type: GspType::GspById,
};

let bios_guid = Guid::new_random();
Expand Down Expand Up @@ -1850,6 +1939,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: true,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::GspById,
encrypt_gsp_type: GspType::GspById,
};

let bios_guid = Guid::new_random();
Expand Down Expand Up @@ -1939,6 +2030,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: true,
use_hardware_unlock: true,
decrypt_gsp_type: GspType::GspById,
encrypt_gsp_type: GspType::GspById,
};
persist_all_key_protectors(
&mut vmgs,
Expand Down Expand Up @@ -1974,6 +2067,8 @@ mod tests {
should_write_kp: false,
use_gsp_by_id: true,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::GspById,
encrypt_gsp_type: GspType::GspById,
};
persist_all_key_protectors(
&mut vmgs,
Expand Down Expand Up @@ -2016,6 +2111,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: false,
use_hardware_unlock: false,
decrypt_gsp_type: GspType::None,
encrypt_gsp_type: GspType::None,
};
persist_all_key_protectors(
&mut vmgs,
Expand Down Expand Up @@ -2061,6 +2158,8 @@ mod tests {
should_write_kp: true,
use_gsp_by_id: false,
use_hardware_unlock: true,
decrypt_gsp_type: GspType::None,
encrypt_gsp_type: GspType::None,
};

persist_all_key_protectors(
Expand Down
1 change: 1 addition & 0 deletions openhcl/underhill_core/src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2676,6 +2676,7 @@ async fn new_underhill_vm(
guest_secret_key: platform_attestation_data.guest_secret_key,
logger: Some(GetTpmLoggerHandle.into_resource()),
is_confidential_vm: isolation.is_isolated(),
bios_guid: dps.general.bios_guid,
}
.into_resource(),
});
Expand Down
2 changes: 2 additions & 0 deletions openvmm/hvlite_core/src/worker/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2558,6 +2558,7 @@ impl LoadedVmInner {
enable_vpci_boot,
uefi_console_mode,
default_boot_always_attempt,
bios_guid,
} => {
let madt = acpi_builder.build_madt();
let srat = acpi_builder.build_srat();
Expand All @@ -2574,6 +2575,7 @@ impl LoadedVmInner {
serial: enable_serial,
uefi_console_mode,
default_boot_always_attempt,
bios_guid,
};
let regs = super::vm_loaders::uefi::load_uefi(
firmware,
Expand Down
3 changes: 2 additions & 1 deletion openvmm/hvlite_core/src/worker/vm_loaders/uefi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub struct UefiLoadSettings {
pub serial: bool,
pub uefi_console_mode: Option<UefiConsoleMode>,
pub default_boot_always_attempt: bool,
pub bios_guid: Guid,
}

/// Loads the UEFI firmware.
Expand Down Expand Up @@ -126,7 +127,7 @@ pub fn load_uefi(
.add_raw(config::BlobStructureType::Madt, madt)
.add_raw(config::BlobStructureType::Srat, srat)
.add_raw(config::BlobStructureType::MemoryMap, memory_map.as_bytes())
.add(&config::BiosGuid(Guid::new_random()))
.add(&config::BiosGuid(load_settings.bios_guid))
.add(&config::Entropy(entropy))
.add(&config::MmioRanges([
config::Mmio {
Expand Down
1 change: 1 addition & 0 deletions openvmm/hvlite_defs/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ pub enum LoadMode {
enable_vpci_boot: bool,
uefi_console_mode: Option<UefiConsoleMode>,
default_boot_always_attempt: bool,
bios_guid: Guid,
},
Pcat {
firmware: RomFileLocation,
Expand Down
Loading
Loading