openhcl_attestation_protocol/igvm_attest/
get.rs1use open_enum::open_enum;
9use zerocopy::FromBytes;
10use zerocopy::Immutable;
11use zerocopy::IntoBytes;
12use zerocopy::KnownLayout;
13
14const ATTESTATION_VERSION: u32 = 2;
15const ATTESTATION_SIGNATURE: u32 = 0x414c4348; const ATTESTATION_REPORT_SIZE_MAX: usize = SNP_VM_REPORT_SIZE;
19
20pub const VBS_VM_REPORT_SIZE: usize = 0x230;
21pub const SNP_VM_REPORT_SIZE: usize = sev_guest_device::protocol::SNP_REPORT_SIZE;
22pub const TDX_VM_REPORT_SIZE: usize = tdx_guest_device::protocol::TDX_REPORT_SIZE;
23pub const TVM_REPORT_SIZE: usize = 0;
25
26const PAGE_SIZE: usize = 4096;
27
28pub const WRAPPED_KEY_RESPONSE_BUFFER_SIZE: usize = 16 * PAGE_SIZE;
31pub const KEY_RELEASE_RESPONSE_BUFFER_SIZE: usize = 16 * PAGE_SIZE;
34pub const AK_CERT_RESPONSE_BUFFER_SIZE: usize = PAGE_SIZE;
37
38pub const AK_CERT_RESPONSE_HEADER_VERSION: u32 = 1;
40
41#[repr(C)]
45#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
46pub struct IgvmAttestRequest {
47 pub header: IgvmAttestRequestHeader,
49 pub attestation_report: [u8; ATTESTATION_REPORT_SIZE_MAX],
51 pub request_data: IgvmAttestRequestData,
53 }
58
59open_enum! {
60 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
62 pub enum IgvmAttestReportType: u32 {
63 INVALID_REPORT = 0,
65 VBS_VM_REPORT = 1,
67 SNP_VM_REPORT = 2,
69 TVM_REPORT = 3,
71 TDX_VM_REPORT = 4,
73 }
74}
75
76open_enum! {
77 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
79 pub enum IgvmAttestRequestType: u32 {
80 INVALID_REQUEST = 0,
82 KEY_RELEASE_REQUEST = 1,
84 AK_CERT_REQUEST = 2,
86 WRAPPED_KEY_REQUEST = 3,
88 }
89}
90
91open_enum! {
92 #[derive(IntoBytes, Immutable, KnownLayout, FromBytes)]
94 pub enum IgvmAttestHashType: u32 {
95 INVALID_HASH = 0,
97 SHA_256 = 1,
99 SHA_384 = 2,
101 SHA_512 = 3,
103 }
104}
105
106#[repr(C)]
108#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
109pub struct IgvmAttestRequestHeader {
110 pub signature: u32,
112 pub version: u32,
114 pub report_size: u32,
116 pub request_type: IgvmAttestRequestType,
118 pub status: u32,
120 pub reserved: [u32; 3],
122}
123
124impl IgvmAttestRequestHeader {
125 pub fn new(report_size: u32, request_type: IgvmAttestRequestType, status: u32) -> Self {
127 Self {
128 signature: ATTESTATION_SIGNATURE,
129 version: ATTESTATION_VERSION,
130 report_size,
131 request_type,
132 status,
133 reserved: [0u32; 3],
134 }
135 }
136}
137
138const IGVM_ATTEST_VERSION_CURRENT: u32 = 1;
139
140#[repr(C)]
142#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
143pub struct IgvmAttestRequestData {
144 pub data_size: u32,
146 pub version: u32,
148 pub report_type: IgvmAttestReportType,
150 pub report_data_hash_type: IgvmAttestHashType,
152 pub variable_data_size: u32,
154}
155
156impl IgvmAttestRequestData {
157 pub fn new(
159 data_size: u32,
160 report_type: IgvmAttestReportType,
161 report_data_hash_type: IgvmAttestHashType,
162 variable_data_size: u32,
163 ) -> Self {
164 Self {
165 data_size,
166 version: IGVM_ATTEST_VERSION_CURRENT,
167 report_type,
168 report_data_hash_type,
169 variable_data_size,
170 }
171 }
172}
173
174#[repr(C)]
178#[derive(Default, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
179pub struct IgvmAttestKeyReleaseResponseHeader {
180 pub data_size: u32,
182 pub version: u32,
184}
185
186#[repr(C)]
191#[derive(Default, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
192pub struct IgvmAttestWrappedKeyResponseHeader {
193 pub data_size: u32,
195 pub version: u32,
197}
198
199#[repr(C)]
203#[derive(Default, Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
204pub struct IgvmAttestAkCertResponseHeader {
205 pub data_size: u32,
207 pub version: u32,
209}
210
211pub mod runtime_claims {
214 use base64_serde::base64_serde_type;
215 use mesh::MeshPayload;
216 use serde::Deserialize;
217 use serde::Serialize;
218
219 base64_serde_type!(Base64Url, base64::engine::general_purpose::URL_SAFE_NO_PAD);
220
221 #[derive(Debug, Deserialize, Serialize)]
225 #[serde(rename_all = "kebab-case")]
226 pub struct RuntimeClaims {
227 pub keys: Vec<RsaJwk>,
229 pub vm_configuration: AttestationVmConfig,
231 #[serde(default, skip_serializing_if = "String::is_empty")]
233 pub user_data: String,
234 }
235
236 impl RuntimeClaims {
237 pub fn key_release_request_runtime_claims(
239 exponent: &[u8],
240 modulus: &[u8],
241 attestation_vm_config: &AttestationVmConfig,
242 ) -> Self {
243 let transfer_key_jwks = RsaJwk::get_transfer_key_jwks(exponent, modulus);
244 Self {
245 keys: transfer_key_jwks,
246 vm_configuration: attestation_vm_config.clone(),
247 user_data: "".to_string(),
248 }
249 }
250
251 pub fn ak_cert_runtime_claims(
253 ak_pub_exponent: &[u8],
254 ak_pub_modulus: &[u8],
255 ek_pub_exponent: &[u8],
256 ek_pub_modulus: &[u8],
257 attestation_vm_config: &AttestationVmConfig,
258 user_data: &[u8],
259 ) -> Self {
260 let tpm_jwks = RsaJwk::get_tpm_jwks(
261 ak_pub_exponent,
262 ak_pub_modulus,
263 ek_pub_exponent,
264 ek_pub_modulus,
265 );
266 Self {
267 keys: tpm_jwks,
268 vm_configuration: attestation_vm_config.clone(),
269 user_data: hex::encode(user_data),
270 }
271 }
272 }
273
274 #[derive(Debug, Deserialize, Serialize)]
276 pub struct RsaJwk {
277 pub kid: String,
279 pub key_ops: Vec<String>,
281 pub kty: String,
283 #[serde(with = "Base64Url")]
285 pub e: Vec<u8>,
286 #[serde(with = "Base64Url")]
288 pub n: Vec<u8>,
289 }
290
291 impl RsaJwk {
292 pub fn get_transfer_key_jwks(exponent: &[u8], modulus: &[u8]) -> Vec<RsaJwk> {
294 let jwk = RsaJwk {
295 kid: "HCLTransferKey".to_string(),
296 key_ops: vec!["encrypt".to_string()],
297 kty: "RSA".to_string(),
298 e: exponent.to_vec(),
299 n: modulus.to_vec(),
300 };
301
302 vec![jwk]
303 }
304
305 pub fn get_tpm_jwks(
307 ak_pub_exponent: &[u8],
308 ak_pub_modulus: &[u8],
309 ek_pub_exponent: &[u8],
310 ek_pub_modulus: &[u8],
311 ) -> Vec<RsaJwk> {
312 let ak_pub = RsaJwk {
313 kid: "HCLAkPub".to_string(),
314 key_ops: vec!["sign".to_string()],
315 kty: "RSA".to_string(),
316 e: ak_pub_exponent.to_vec(),
317 n: ak_pub_modulus.to_vec(),
318 };
319 let ek_pub = RsaJwk {
320 kid: "HCLEkPub".to_string(),
321 key_ops: vec!["encrypt".to_string()],
322 kty: "RSA".to_string(),
323 e: ek_pub_exponent.to_vec(),
324 n: ek_pub_modulus.to_vec(),
325 };
326
327 vec![ak_pub, ek_pub]
328 }
329 }
330
331 #[derive(Clone, Debug, Deserialize, Serialize, MeshPayload)]
333 #[serde(rename_all = "kebab-case")]
334 pub struct AttestationVmConfig {
335 #[serde(skip_serializing_if = "Option::is_none")]
337 pub current_time: Option<i64>,
338 pub root_cert_thumbprint: String,
340 pub console_enabled: bool,
342 pub secure_boot: bool,
344 pub tpm_enabled: bool,
346 pub tpm_persisted: bool,
348 #[serde(rename = "vmUniqueId")]
350 pub vm_unique_id: String,
351 }
352}