islet_rmm/rmi/
metadata.rs1use core::ffi::CStr;
2use p384::{
3 ecdsa::{signature::Verifier, Signature, VerifyingKey},
4 elliptic_curve::generic_array::GenericArray,
5 EncodedPoint,
6};
7
8use super::{HASH_ALGO_SHA256, HASH_ALGO_SHA512};
9use crate::granule::GRANULE_SIZE;
10use crate::measurement::{Measurement, MEASUREMENTS_SLOT_MAX_SIZE};
11use crate::rmi::error::Error;
12
13const FMT_VERSION: usize = 1;
14pub const REALM_ID_SIZE: usize = 128;
15pub const P384_PUBLIC_KEY_SIZE: usize = 96;
16const P384_SIGNATURE_SIZE: usize = P384_PUBLIC_KEY_SIZE;
17
18#[allow(dead_code)]
19const P385_SIGNATURE_POINT_SIZE: usize = P384_SIGNATURE_SIZE / 2;
20#[allow(dead_code)]
21const SHA_384_HASH_SIZE: usize = 48;
22
23const METADATA_HASH_SHA_256: usize = 0x01;
24const METADATA_HASH_SHA_512: usize = 0x02;
25
26const REALM_METADATA_HEADER_SIZE: usize = 0x150;
27#[allow(dead_code)]
28const REALM_METADATA_SIGNED_SIZE: usize = 0x1B0;
29const REALM_METADATA_UNUSED_SIZE: usize = 0xE50;
30
31#[derive(Debug, Clone, Copy)]
32#[repr(C)]
33pub struct IsletRealmMetadata {
34 fmt_version: usize,
35 realm_id: [u8; REALM_ID_SIZE],
36 rim: [u8; MEASUREMENTS_SLOT_MAX_SIZE],
37 hash_algo: usize,
38 svn: usize,
39 version_major: usize,
40 version_minor: usize,
41 version_patch: usize,
42 public_key: [u8; P384_PUBLIC_KEY_SIZE],
43 signature: [u8; P384_SIGNATURE_SIZE],
44 _unused: [u8; REALM_METADATA_UNUSED_SIZE],
45}
46
47const _: () = assert!(core::mem::size_of::<IsletRealmMetadata>() == GRANULE_SIZE);
48const _: () = assert!(core::mem::size_of::<IsletRealmMetadata>() >= REALM_METADATA_SIGNED_SIZE);
49
50const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, fmt_version) == 0x00);
51const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, realm_id) == 0x08);
52const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, rim) == 0x88);
53const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, hash_algo) == 0xc8);
54const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, svn) == 0xd0);
55const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, version_major) == 0xd8);
56const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, version_minor) == 0xe0);
57const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, version_patch) == 0xe8);
58const _: () = assert!(core::mem::offset_of!(IsletRealmMetadata, public_key) == 0xf0);
59
60impl IsletRealmMetadata {
61 fn realm_id_as_str(&self) -> Option<&str> {
62 let Ok(cstr) = CStr::from_bytes_until_nul(&self.realm_id) else {
63 return None;
64 };
65 let Ok(s) = cstr.to_str() else {
66 return None;
67 };
68 Some(s)
69 }
70
71 pub fn dump(&self) {
72 debug!("fmt_version: {:#010x}", self.fmt_version);
73 debug!(
74 "realm_id: {}",
75 self.realm_id_as_str().unwrap_or("INVALID REALM ID")
76 );
77 debug!("rim: {}", hex::encode(self.rim));
78 debug!("hash_algo: {:#010x}", self.hash_algo);
79 debug!("svn: {:#010x}", self.svn);
80 debug!("version_major: {:#010x}", self.version_major);
81 debug!("version_minor: {:#010x}", self.version_minor);
82 debug!("version_patch: {:#010x}", self.version_patch);
83 debug!("public_key: {}", hex::encode(self.public_key));
84 debug!("signature: {}", hex::encode(self.signature));
85 }
86
87 fn verifying_key(&self) -> core::result::Result<VerifyingKey, Error> {
88 let point = EncodedPoint::from_untagged_bytes(GenericArray::from_slice(&self.public_key));
89 VerifyingKey::from_encoded_point(&point).or(Err(Error::RmiErrorInput))
90 }
91
92 fn signature(&self) -> core::result::Result<Signature, Error> {
93 Signature::from_slice(&self.signature).or(Err(Error::RmiErrorInput))
94 }
95
96 fn header_as_u8_slice(&self) -> &[u8] {
97 let slice = unsafe {
98 core::slice::from_raw_parts(
99 (self as *const Self) as *const u8,
100 core::mem::size_of::<Self>(),
101 )
102 };
103 &slice[..REALM_METADATA_HEADER_SIZE]
104 }
105
106 pub fn verify_signature(&self) -> core::result::Result<(), Error> {
107 let verifying_key = self.verifying_key()?;
108 let signature = self.signature()?;
109 let data = self.header_as_u8_slice();
110
111 verifying_key
112 .verify(data, &signature)
113 .or(Err(Error::RmiErrorInput))
114 }
115
116 pub fn validate(&self) -> core::result::Result<(), Error> {
117 if self.fmt_version != FMT_VERSION {
118 error!(
119 "Metadata format version {} is not supported!",
120 self.fmt_version
121 );
122 Err(Error::RmiErrorInput)?
123 }
124
125 if self.svn == 0 {
126 error!("SVN number should be greater than zero");
127 Err(Error::RmiErrorInput)?
128 }
129
130 if ![METADATA_HASH_SHA_256, METADATA_HASH_SHA_512].contains(&self.hash_algo) {
131 error!("Hash algorithm is invalid {}", self.hash_algo);
132 Err(Error::RmiErrorInput)?
133 }
134
135 let is_printable_ascii = |&c| c >= b' ' && c <= b'~';
136
137 if !self
138 .realm_id
139 .iter()
140 .take_while(|&c| *c != b'\0')
141 .all(is_printable_ascii)
142 {
143 error!("Realm id is invalid");
144 Err(Error::RmiErrorInput)?
145 }
146
147 Ok(())
148 }
149
150 pub fn equal_rd_rim(&self, rim: &Measurement) -> bool {
151 rim.as_slice() == self.rim
152 }
153
154 pub fn equal_rd_hash_algo(&self, hash_algo: u8) -> bool {
155 let converted_algo = match hash_algo {
156 HASH_ALGO_SHA256 => METADATA_HASH_SHA_256,
157 HASH_ALGO_SHA512 => METADATA_HASH_SHA_512,
158 _ => unreachable!(),
159 };
160
161 converted_algo == self.hash_algo
162 }
163
164 pub fn svn(&self) -> usize {
167 self.svn
168 }
169
170 pub fn public_key(&self) -> &[u8; P384_PUBLIC_KEY_SIZE] {
171 &self.public_key
172 }
173
174 pub fn realm_id(&self) -> &[u8; REALM_ID_SIZE] {
175 &self.realm_id
176 }
177}
178
179impl vmsa::guard::Content for IsletRealmMetadata {}
181impl safe_abstraction::raw_ptr::RawPtr for IsletRealmMetadata {}
182impl safe_abstraction::raw_ptr::SafetyChecked for IsletRealmMetadata {}
183impl safe_abstraction::raw_ptr::SafetyAssured for IsletRealmMetadata {
184 fn is_initialized(&self) -> bool {
185 true
186 }
187
188 fn verify_ownership(&self) -> bool {
189 true
190 }
191}