Skip to content

Commit 5fb0519

Browse files
feat: add checks for confidential compute (#76)
Add support for cc attestation generation, as well as cert chain support. Check for cc capabilities of the node, as well if node is in ready state for cc
1 parent 04af00c commit 5fb0519

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

nvml-wrapper/src/device.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,154 @@ impl<'nvml> Device<'nvml> {
850850
}
851851
}
852852

853+
/**
854+
Checks simultaneously if confidential compute is enabled, if the device is in a production environment,
855+
and if the device is accepting client requests.
856+
# Errors
857+
* `Uninitialized`, if the library has not been successfully initialized
858+
* `NotSupported`, if this query is not supported by the device
859+
* `InvalidArg`, if confidential compute state is invalid
860+
*/
861+
pub fn check_confidential_compute_status(&self) -> Result<bool, NvmlError> {
862+
let cc_state_sym = nvml_sym(self.nvml.lib.nvmlSystemGetConfComputeState.as_ref())?;
863+
let cc_gpus_ready_sym = nvml_sym(
864+
self.nvml
865+
.lib
866+
.nvmlSystemGetConfComputeGpusReadyState
867+
.as_ref(),
868+
)?;
869+
870+
unsafe {
871+
let mut state: nvmlConfComputeSystemState_t = mem::zeroed();
872+
nvml_try(cc_state_sym(&mut state))?;
873+
874+
let is_cc_enabled = state.ccFeature == NVML_CC_SYSTEM_FEATURE_ENABLED;
875+
let is_prod_environment = state.environment == NVML_CC_SYSTEM_ENVIRONMENT_PROD;
876+
877+
let mut cc_gpus_ready: std::os::raw::c_uint = 0;
878+
nvml_try(cc_gpus_ready_sym(&mut cc_gpus_ready))?;
879+
let is_accepting_client_requests =
880+
cc_gpus_ready == NVML_CC_ACCEPTING_CLIENT_REQUESTS_TRUE;
881+
882+
Ok(is_cc_enabled && is_prod_environment && is_accepting_client_requests)
883+
}
884+
}
885+
886+
/**
887+
Gets the confidential compute capabilities for this `Device`.
888+
# Errors
889+
* `Uninitialized`, if the library has not been successfully initialized
890+
* `InvalidArg`, if device is invalid or memory is NULL
891+
* `NotSupported`, if this query is not supported by the device
892+
* `Unknown`, on any unexpected error
893+
*/
894+
pub fn get_confidential_compute_capabilities(
895+
&self,
896+
) -> Result<ConfidentialComputeCapabilities, NvmlError> {
897+
let sym = nvml_sym(self.nvml.lib.nvmlSystemGetConfComputeCapabilities.as_ref())?;
898+
899+
unsafe {
900+
let mut capabilities: nvmlConfComputeSystemCaps_t = mem::zeroed();
901+
nvml_try(sym(&mut capabilities))?;
902+
903+
let cpu_caps = match capabilities.cpuCaps {
904+
NVML_CC_SYSTEM_CPU_CAPS_NONE => ConfidentialComputeCpuCapabilities::None,
905+
NVML_CC_SYSTEM_CPU_CAPS_AMD_SEV => ConfidentialComputeCpuCapabilities::AmdSev,
906+
NVML_CC_SYSTEM_CPU_CAPS_INTEL_TDX => ConfidentialComputeCpuCapabilities::IntelTdx,
907+
_ => return Err(NvmlError::Unknown),
908+
};
909+
910+
let gpus_caps = match capabilities.gpusCaps {
911+
NVML_CC_SYSTEM_GPUS_CC_CAPABLE => ConfidentialComputeGpuCapabilities::Capable,
912+
NVML_CC_SYSTEM_GPUS_CC_NOT_CAPABLE => {
913+
ConfidentialComputeGpuCapabilities::NotCapable
914+
}
915+
_ => return Err(NvmlError::Unknown),
916+
};
917+
918+
Ok(ConfidentialComputeCapabilities {
919+
cpu_caps,
920+
gpus_caps,
921+
})
922+
}
923+
}
924+
925+
/**
926+
Gets the confidential compute GPU certificate for this `Device`.
927+
# Errors
928+
* `Uninitialized` if the library has not been successfully initialized
929+
* `InvalidArg` if device is invalid or memory is NULL
930+
* `NotSupported` if this query is not supported by the device
931+
* `Unknown` on any unexpected error
932+
*/
933+
pub fn confidential_compute_gpu_certificate(
934+
&self,
935+
) -> Result<ConfidentialComputeGpuCertificate, NvmlError> {
936+
let sym = nvml_sym(
937+
self.nvml
938+
.lib
939+
.nvmlDeviceGetConfComputeGpuCertificate
940+
.as_ref(),
941+
)?;
942+
943+
unsafe {
944+
let mut certificate_chain: nvmlConfComputeGpuCertificate_t = mem::zeroed();
945+
nvml_try(sym(self.device, &mut certificate_chain))?;
946+
947+
Ok(ConfidentialComputeGpuCertificate {
948+
cert_chain_size: certificate_chain.certChainSize,
949+
attestation_cert_chain_size: certificate_chain.attestationCertChainSize,
950+
cert_chain: certificate_chain.certChain.to_vec(),
951+
attestation_cert_chain: certificate_chain.attestationCertChain.to_vec(),
952+
})
953+
}
954+
}
955+
956+
/**
957+
Fetches the confidential compute attestation report for this [`Device`].
958+
This method retrieves a comprehensive attestation report from the device, which includes:
959+
- A 32-byte nonce
960+
- The attestation report size (as big-endian bytes)
961+
- The attestation report data (up to 8192 bytes)
962+
- A flag indicating if CEC attestation is present (as big-endian bytes)
963+
- The CEC attestation report size (as big-endian bytes)
964+
- The CEC attestation report data (up to 4096 bytes)
965+
The returned vector contains all these components concatenated together in the order listed above.
966+
# Errors
967+
* `Uninitialized`, if the library has not been successfully initialized
968+
* `InvalidArg`, if device is invalid or memory is NULL
969+
* `NotSupported`, if this query is not supported by the device
970+
* `Unknown`, on any unexpected error
971+
*/
972+
#[doc(alias = "nvmlDeviceGetAttestationReport")]
973+
pub fn confidential_compute_gpu_attestation_report(
974+
&self,
975+
nonce: [u8; NVML_CC_GPU_CEC_NONCE_SIZE as usize],
976+
) -> Result<ConfidentialComputeGpuAttestationReport, NvmlError> {
977+
let sym = nvml_sym(
978+
self.nvml
979+
.lib
980+
.nvmlDeviceGetConfComputeGpuAttestationReport
981+
.as_ref(),
982+
)?;
983+
984+
unsafe {
985+
let mut report: nvmlConfComputeGpuAttestationReport_st = mem::zeroed();
986+
report.nonce = nonce;
987+
988+
nvml_try(sym(self.device, &mut report))?;
989+
990+
let is_cec_attestation_report_present = report.isCecAttestationReportPresent == 1;
991+
Ok(ConfidentialComputeGpuAttestationReport {
992+
attestation_report_size: report.attestationReportSize,
993+
attestation_report: report.attestationReport.to_vec(),
994+
is_cec_attestation_report_present,
995+
cec_attestation_report_size: report.cecAttestationReportSize,
996+
cec_attestation_report: report.cecAttestationReport.to_vec(),
997+
})
998+
}
999+
}
1000+
8531001
/**
8541002
Gets the current utilization and sampling size (sampling size in μs) for the Decoder.
8551003

nvml-wrapper/src/structs/device.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,3 +119,69 @@ pub struct RetiredPage {
119119
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
120120
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
121121
pub struct FieldId(pub u32);
122+
123+
/// Returned from `Device.get_confidential_compute_capabilities()`
124+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
125+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
126+
pub struct ConfidentialComputeCapabilities {
127+
/// The CPU capabilities.
128+
pub cpu_caps: ConfidentialComputeCpuCapabilities,
129+
/// The GPU capabilities.
130+
pub gpus_caps: ConfidentialComputeGpuCapabilities,
131+
}
132+
133+
/// The possible CPU capabilities for confidential compute (either None, AMD SEV or Intel TDX)
134+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
135+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
136+
pub enum ConfidentialComputeCpuCapabilities {
137+
/// No CPU capabilities.
138+
None,
139+
/// AMD SEV confidential compute capabilities.
140+
AmdSev,
141+
/// Intel TDX confidential compute capabilities.
142+
IntelTdx,
143+
}
144+
145+
/// The possible GPU capabilities for confidential compute (either not capable or capable)
146+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
147+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
148+
pub enum ConfidentialComputeGpuCapabilities {
149+
/// Capable.
150+
Capable,
151+
/// Not capable.
152+
NotCapable,
153+
}
154+
155+
/// Returned from `Device.confidential_compute_gpu_certificate()`
156+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
157+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
158+
pub struct ConfidentialComputeGpuCertificate {
159+
/// The size of the certificate chain.
160+
pub cert_chain_size: u32,
161+
/// The size of the attestation certificate chain.
162+
pub attestation_cert_chain_size: u32,
163+
/// The certificate chain, of size
164+
/// `ffi::bindings::NVML_GPU_CERT_CHAIN_SIZE == 4096`.
165+
pub cert_chain: Vec<u8>,
166+
/// The attestation certificate chain, of size
167+
/// `ffi::bindings::NVML_GPU_ATTESTATION_CERT_CHAIN_SIZE == 5120`.
168+
pub attestation_cert_chain: Vec<u8>,
169+
}
170+
171+
/// Returned from `Device.confidential_compute_gpu_attestation_report_bytes()`
172+
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
173+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
174+
pub struct ConfidentialComputeGpuAttestationReport {
175+
/// The size of the attestation report.
176+
pub attestation_report_size: u32,
177+
/// The attestation report, of size
178+
/// `ffi::bindings::NVML_CC_GPU_ATTESTATION_REPORT_SIZE == 8192`.
179+
pub attestation_report: Vec<u8>,
180+
/// Whether the CEC attestation report is present.
181+
pub is_cec_attestation_report_present: bool,
182+
/// The size of the CEC attestation report.
183+
pub cec_attestation_report_size: u32,
184+
/// The CEC attestation report, of size
185+
/// `ffi::bindings::NVML_CC_GPU_CEC_ATTESTATION_REPORT_SIZE == 4096`.
186+
pub cec_attestation_report: Vec<u8>,
187+
}

0 commit comments

Comments
 (0)