1use core::ffi::CStr;
2
3use crate::granule::GranuleState;
4use crate::measurement::{Measurement, MEASUREMENTS_SLOT_MAX_SIZE, MEASUREMENTS_SLOT_RIM};
5use crate::realm::rd::{Rd, RPV_SIZE};
6use crate::rmi::error::Error;
7use crate::rmi::metadata::{IsletRealmMetadata, P384_PUBLIC_KEY_SIZE, REALM_ID_SIZE};
8use crate::rmm_el3::{vhuk_a, vhuk_m};
9use crate::{get_granule, get_granule_if};
10
11const RSI_ISLET_USE_VHUK_M: usize = 0x1 << 0;
12const RSI_ISLET_SLK_RIM: usize = 0x1 << 1;
13const RSI_ISLET_SLK_REALM_ID: usize = 0x1 << 2;
14const RSI_ISLET_SLK_SVN: usize = 0x1 << 3;
15
16pub const SEALING_KEY_SIZE: usize = 32;
17
18const SALT: [u8; 32] = [
19 0xd5, 0x77, 0x5f, 0x52, 0x4a, 0xce, 0x32, 0x21, 0xce, 0x77, 0x1e, 0xd2, 0x74, 0xbb, 0x74, 0xa4,
20 0x60, 0xce, 0x3f, 0xb9, 0x74, 0x9c, 0xe3, 0x7d, 0x0a, 0xe6, 0xd2, 0xe9, 0x07, 0xf8, 0xb5, 0x4b,
21];
22
23#[repr(C, packed)]
24struct KdfInfo {
25 public_key: [u8; P384_PUBLIC_KEY_SIZE],
26 realm_id: [u8; REALM_ID_SIZE],
27 rpv: [u8; RPV_SIZE],
28 flags: usize,
29 rim: [u8; MEASUREMENTS_SLOT_MAX_SIZE],
30 hash_algo: u8,
31 svn: usize,
32}
33
34impl KdfInfo {
35 fn new() -> Self {
36 Self {
37 public_key: [0; P384_PUBLIC_KEY_SIZE],
38 realm_id: [0; REALM_ID_SIZE],
39 rpv: [0; RPV_SIZE],
40 flags: 0,
41 rim: [0; MEASUREMENTS_SLOT_MAX_SIZE],
42 hash_algo: 0,
43 svn: 0,
44 }
45 }
46
47 fn zeroize(&mut self) {
49 let addr = self as *mut Self;
50 unsafe {
51 core::ptr::write_bytes(addr as *mut u8, 0x0, core::mem::size_of::<Self>());
52 }
53 }
54
55 fn realm_id_as_str(&self) -> Option<&str> {
56 let Ok(cstr) = CStr::from_bytes_until_nul(&self.realm_id) else {
57 return None;
58 };
59 let Ok(s) = cstr.to_str() else {
60 return None;
61 };
62 Some(s)
63 }
64
65 fn dump(&self) {
66 debug!("KDF info");
67 debug!("public_key: {}", hex::encode(self.public_key));
68 debug!(
69 "realm_id: {}",
70 self.realm_id_as_str().unwrap_or("INVALID REALM ID")
71 );
72 debug!("rpv: {}", hex::encode(self.rpv));
73 let flags = self.flags; debug!("flags: {:#010x}", flags);
75 debug!("rim: {}", hex::encode(self.rim));
76 debug!("hash_algo: {:#04x}", self.hash_algo);
77 let svn = self.svn; debug!("svn: {:#010x}", svn);
79 }
80
81 fn as_u8_slice(&self) -> &[u8] {
82 unsafe {
83 core::slice::from_raw_parts(
84 (self as *const Self) as *const u8,
85 core::mem::size_of::<Self>(),
86 )
87 }
88 }
89
90 fn derive_sealing_key(
91 &self,
92 use_vhuk_m: bool,
93 okm: &mut [u8; SEALING_KEY_SIZE],
94 ) -> core::result::Result<(), Error> {
95 let ikm = if use_vhuk_m { vhuk_m() } else { vhuk_a() };
96 let info = self.as_u8_slice();
97
98 let hkdf = hkdf::Hkdf::<sha2::Sha256>::new(Some(&SALT), &ikm);
99 hkdf.expand(info, okm).or(Err(Error::RmiErrorInput))?;
100
101 Ok(())
102 }
103}
104
105pub fn realm_sealing_key(
106 rd: &Rd,
107 flags: usize,
108 svn: usize,
109 buf: &mut [u8; SEALING_KEY_SIZE],
110) -> core::result::Result<(), Error> {
111 debug!("flags: {:#010x}, svn: {:#010x}", flags, svn);
112
113 let mut info = KdfInfo::new();
114
115 info.rpv.copy_from_slice(rd.personalization_value());
116 info.flags = flags;
117
118 if let Some(meta_addr) = rd.metadata() {
119 let metadata_granule = get_granule_if!(meta_addr, GranuleState::Metadata)?;
120 let metadata_obj = metadata_granule.content::<IsletRealmMetadata>()?;
121
122 if flags & RSI_ISLET_SLK_SVN != 0 && metadata_obj.svn() < svn {
123 warn!("The SVN parameter is invalid!");
124 Err(Error::RmiErrorInput)?
125 }
126
127 info.public_key = *metadata_obj.public_key();
128
129 if flags & RSI_ISLET_SLK_REALM_ID != 0 {
130 info.realm_id = *metadata_obj.realm_id();
131 }
132
133 if flags & RSI_ISLET_SLK_SVN != 0 {
134 info.svn = svn;
135 }
136 }
137
138 if flags & RSI_ISLET_SLK_RIM != 0 || rd.metadata().is_none() {
142 let mut rim = Measurement::empty();
143 crate::rsi::measurement::read(rd, MEASUREMENTS_SLOT_RIM, &mut rim)?;
144 info.rim.copy_from_slice(rim.as_slice());
145 }
146
147 info.dump();
148 debug!(
149 "ikm type: {}",
150 if flags & RSI_ISLET_USE_VHUK_M != 0 {
151 "VHUK_M"
152 } else {
153 "VHUK_A"
154 }
155 );
156 info.derive_sealing_key(flags & RSI_ISLET_USE_VHUK_M != 0, buf)?;
157
158 info.zeroize();
160
161 Ok(())
162}