Skip to main content

openhcl_attestation_protocol/
vmgs.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Include modules that define the data structures of VMGS entries.
5
6use zerocopy::FromBytes;
7use zerocopy::Immutable;
8use zerocopy::IntoBytes;
9use zerocopy::KnownLayout;
10
11/// Number of the key protector entries.
12/// One for ingress, and one for egress
13pub const NUMBER_KP: usize = 2;
14
15/// DEK buffer size
16pub const DEK_BUFFER_SIZE: usize = 512;
17
18/// GSP buffer size
19pub const GSP_BUFFER_SIZE: usize = 512;
20
21/// Size of the `FileId::KEY_PROTECTOR` VMGS file entry.
22pub const KEY_PROTECTOR_SIZE: usize = size_of::<KeyProtector>();
23
24/// DEK key protector entry.
25#[repr(C)]
26#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
27pub struct DekKp {
28    /// DEK buffer
29    pub dek_buffer: [u8; DEK_BUFFER_SIZE],
30}
31
32/// GSP key protector entry.
33#[repr(C)]
34#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
35pub struct GspKp {
36    /// GSP data size
37    pub gsp_length: u32,
38    /// GSP buffer
39    pub gsp_buffer: [u8; GSP_BUFFER_SIZE],
40}
41
42/// The data format of the `FileId::KEY_PROTECTOR` entry in the VMGS file.
43#[repr(C)]
44#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
45pub struct KeyProtector {
46    /// Array of DEK entries
47    pub dek: [DekKp; NUMBER_KP],
48    /// Array of GSP entries
49    pub gsp: [GspKp; NUMBER_KP],
50    /// Index of the activate entry
51    pub active_kp: u32,
52}
53
54/// The data format of the host/fabric-provided key protector.
55#[repr(C)]
56#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
57pub struct KeyProtectorById {
58    /// Id
59    pub id_guid: guid::Guid,
60    /// Ported (boolean)
61    pub ported: u8,
62    /// Padding
63    pub pad: [u8; 3],
64}
65
66/// Maximum size of the `agent_data`.
67pub const AGENT_DATA_MAX_SIZE: usize = 2048;
68
69/// The data format of the `FileId::ATTEST` entry in the VMGS file.
70#[repr(C)]
71#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
72pub struct SecurityProfile {
73    /// the agent data used during attestation requests
74    pub agent_data: [u8; AGENT_DATA_MAX_SIZE],
75}
76
77/// VMGS hardware key protector entry that includes the metadata of
78/// local hardware sealing with AES-CBC-HMAC-SHA256.
79///
80/// Version 1 is incompatible with newer versions.
81/// Version 2 or newer is forward-compatible if header.mix_measurement is not set.
82pub const HW_KEY_PROTECTOR_VERSION_1: u32 = 1;
83pub const HW_KEY_PROTECTOR_VERSION_2: u32 = 2;
84/// Version 3 is a unified, TEE-tagged format used for all newly-created
85/// protectors (SNP and TDX). It records the raw report SVNs so the derived key
86/// can bind every SVN the TEE mixes in (for TDX, both `TEE_TCB_SVN` and
87/// `CPU_SVN`) rather than a lossy `u64`. v2 is retained read-only for legacy SNP
88/// protectors.
89pub const HW_KEY_PROTECTOR_VERSION_3: u32 = 3;
90pub const HW_KEY_PROTECTOR_CURRENT_VERSION: u32 = HW_KEY_PROTECTOR_VERSION_3;
91
92/// TEE tag stored in [`HardwareKeyProtectorHeaderV3::tee_type`].
93pub const HW_KEY_PROTECTOR_TEE_TYPE_SNP: u32 = 0;
94/// TEE tag stored in [`HardwareKeyProtectorHeaderV3::tee_type`].
95pub const HW_KEY_PROTECTOR_TEE_TYPE_TDX: u32 = 1;
96
97/// The size of the `FileId::HW_KEY_PROTECTOR` entry in the VMGS file.
98pub const HW_KEY_PROTECTOR_SIZE: usize = size_of::<HardwareKeyProtector>();
99
100/// The size of a version-3 `FileId::HW_KEY_PROTECTOR` entry.
101pub const HW_KEY_PROTECTOR_V3_SIZE: usize = size_of::<HardwareKeyProtectorV3>();
102
103// Readers dispatch on the entry size to tell the legacy layout apart from v3,
104// so the two must never collide.
105const _: () = assert!(HW_KEY_PROTECTOR_SIZE != HW_KEY_PROTECTOR_V3_SIZE);
106
107/// Size of the TEE-specific SVN blob in [`HardwareKeyProtectorHeaderV3`].
108pub const HW_KEY_PROTECTOR_SVN_SIZE: usize = 32;
109
110/// AES-GCM key size
111pub const AES_GCM_KEY_LENGTH: usize = 32;
112
113/// AES-CBC key size
114pub const AES_CBC_KEY_LENGTH: usize = AES_GCM_KEY_LENGTH;
115
116/// AES-CBC IV size
117pub const AES_CBC_IV_LENGTH: usize = 16;
118
119/// HMAC-SHA-256 key size
120pub const HMAC_SHA_256_KEY_LENGTH: usize = 32;
121
122/// The header of [`HardwareKeyProtector`].
123#[repr(C)]
124#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
125pub struct HardwareKeyProtectorHeader {
126    /// Version of the format
127    pub version: u32,
128    /// Size of the [`HardwareKeyProtector`] data blob
129    pub length: u32,
130    /// TCB version obtained from the hardware
131    pub tcb_version: u64,
132    /// Whether to mix the measurement in hardware key derivation
133    /// Only supported in version 2 and above
134    pub mix_measurement: u8,
135    /// Reserved bytes for future use
136    pub _reserved: [u8; 7],
137}
138
139impl HardwareKeyProtectorHeader {
140    /// Create a `HardwareKeyProtectorHeader` instance.
141    pub fn new(version: u32, length: u32, tcb_version: u64, mix_measurement: u8) -> Self {
142        Self {
143            version,
144            length,
145            tcb_version,
146            mix_measurement,
147            _reserved: [0; 7],
148        }
149    }
150}
151
152/// The data format of the `FileId::HW_KEY_PROTECTOR` entry in the VMGS file.
153#[repr(C)]
154#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
155pub struct HardwareKeyProtector {
156    /// Header
157    pub header: HardwareKeyProtectorHeader,
158    /// Random IV for AES-CBC
159    pub iv: [u8; AES_CBC_IV_LENGTH],
160    /// Encrypted key
161    pub ciphertext: [u8; AES_GCM_KEY_LENGTH],
162    /// HMAC-SHA-256 of [header, iv, ciphertext]
163    pub hmac: [u8; HMAC_SHA_256_KEY_LENGTH],
164}
165
166/// Version-3 header. Shares the `version`/`length` prefix with
167/// [`HardwareKeyProtectorHeader`] so the version can be read first, then carries
168/// a TEE-tagged SVN blob bound into the derived key.
169///
170/// `svn` layout by `tee_type`:
171/// - [`HW_KEY_PROTECTOR_TEE_TYPE_SNP`]: `reported_tcb` (u64, little-endian) in
172///   bytes `0..8`; bytes `8..32` zero.
173/// - [`HW_KEY_PROTECTOR_TEE_TYPE_TDX`]: `TEE_TCB_SVN` in bytes `0..16` and
174///   `CPU_SVN` in bytes `16..32`.
175#[repr(C)]
176#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
177pub struct HardwareKeyProtectorHeaderV3 {
178    /// Version of the format (== [`HW_KEY_PROTECTOR_VERSION_3`]).
179    pub version: u32,
180    /// Size of the [`HardwareKeyProtectorV3`] data blob.
181    pub length: u32,
182    /// TEE that produced the SVNs (see `HW_KEY_PROTECTOR_TEE_TYPE_*`).
183    pub tee_type: u32,
184    /// TEE-specific SVN material recorded at seal time.
185    pub svn: [u8; HW_KEY_PROTECTOR_SVN_SIZE],
186    /// Whether to mix the measurement in hardware key derivation.
187    pub mix_measurement: u8,
188    /// Reserved bytes for future use.
189    pub _reserved: [u8; 3],
190}
191
192impl HardwareKeyProtectorHeaderV3 {
193    /// Create a `HardwareKeyProtectorHeaderV3` instance.
194    pub fn new(
195        length: u32,
196        tee_type: u32,
197        svn: [u8; HW_KEY_PROTECTOR_SVN_SIZE],
198        mix_measurement: u8,
199    ) -> Self {
200        Self {
201            version: HW_KEY_PROTECTOR_VERSION_3,
202            length,
203            tee_type,
204            svn,
205            mix_measurement,
206            _reserved: [0; 3],
207        }
208    }
209}
210
211/// Version-3 data format of the `FileId::HW_KEY_PROTECTOR` entry.
212#[repr(C)]
213#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
214pub struct HardwareKeyProtectorV3 {
215    /// Header
216    pub header: HardwareKeyProtectorHeaderV3,
217    /// Random IV for AES-CBC
218    pub iv: [u8; AES_CBC_IV_LENGTH],
219    /// Encrypted key
220    pub ciphertext: [u8; AES_GCM_KEY_LENGTH],
221    /// HMAC-SHA-256 of [header, iv, ciphertext]
222    pub hmac: [u8; HMAC_SHA_256_KEY_LENGTH],
223}
224
225/// Maximum size of the `guest_secret_key`.
226pub const GUEST_SECRET_KEY_MAX_SIZE: usize = 2048;
227
228/// The data format of the `FileId::GUEST_SECRET_KEY` entry in the VMGS file.
229#[repr(C)]
230#[derive(Debug, IntoBytes, Immutable, KnownLayout, FromBytes)]
231pub struct GuestSecretKey {
232    /// the guest secret key to be provisioned to vTPM
233    pub guest_secret_key: [u8; GUEST_SECRET_KEY_MAX_SIZE],
234}
235
236#[cfg(test)]
237mod tests {
238    use super::*;
239
240    #[test]
241    fn hardware_key_protector_header_new() {
242        let h = HardwareKeyProtectorHeader::new(2, 104, 0x1234, 1);
243        assert_eq!(h.version, 2);
244        assert_eq!(h.length, 104);
245        assert_eq!(h.tcb_version, 0x1234);
246        assert_eq!(h.mix_measurement, 1);
247        assert_eq!(h._reserved, [0; 7]);
248    }
249}