1use std::{borrow::Cow, error::Error as StdError, fmt, io, mem};
2
3use lexe_byte_array::ByteArray;
4use lexe_hex::hex;
5use lexe_serde::impl_serde_hexstr_or_bytes;
6use lexe_sha256::sha256;
7#[cfg(any(test, feature = "test-utils"))]
8use proptest_derive::Arbitrary;
9use ref_cast::RefCast;
10
11#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
18#[derive(Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, RefCast)]
19#[repr(transparent)]
20pub struct Measurement([u8; 32]);
21
22impl_serde_hexstr_or_bytes!(Measurement);
23
24#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
26#[derive(Copy, Clone, Hash, Eq, PartialEq, RefCast)]
27#[repr(transparent)]
28pub struct MrShort([u8; 4]);
29
30impl_serde_hexstr_or_bytes!(MrShort);
31
32pub enum Error {
33 SgxError(sgx_isa::ErrorCode),
34 SealInputTooLarge,
35 UnsealInputTooSmall,
36 InvalidKeyRequestLength,
37 UnsealDecryptionError,
38 DeserializationError,
39}
40
41#[cfg_attr(any(test, feature = "test-utils"), derive(Arbitrary))]
65#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd, RefCast)]
66#[repr(transparent)]
67pub struct MachineId([u8; 16]);
68
69impl_serde_hexstr_or_bytes!(MachineId);
70
71#[derive(Eq, PartialEq)]
75pub struct Sealed<'a> {
76 pub keyrequest: Cow<'a, [u8]>,
82 pub ciphertext: Cow<'a, [u8]>,
84}
85
86#[derive(Copy, Clone)]
99#[repr(transparent)]
100pub(crate) struct MinCpusvn([u8; 16]);
101
102impl StdError for Error {}
105
106impl fmt::Display for Error {
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 let s = match self {
109 Self::SgxError(_) => "",
110 Self::SealInputTooLarge => "sealing: input data is too large",
111 Self::UnsealInputTooSmall => "unsealing: ciphertext is too small",
112 Self::InvalidKeyRequestLength => "keyrequest is not a valid length",
113 Self::UnsealDecryptionError =>
114 "unseal error: ciphertext or metadata may be corrupted",
115 Self::DeserializationError => "deserialize: input is malformed",
116 };
117 match self {
118 Self::SgxError(err) => write!(f, "SGX error: {err:?}"),
119 _ => f.write_str(s),
120 }
121 }
122}
123
124impl fmt::Debug for Error {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 write!(f, "enclave::Error({self})")
127 }
128}
129
130impl From<sgx_isa::ErrorCode> for Error {
131 fn from(err: sgx_isa::ErrorCode) -> Self {
132 Self::SgxError(err)
133 }
134}
135
136impl Measurement {
139 pub const MOCK_ENCLAVE: Self =
140 Self::new(*b"~~~~~~~ LEXE MOCK ENCLAVE ~~~~~~");
141 pub const MOCK_SIGNER: Self =
142 Self::new(*b"======= LEXE MOCK SIGNER =======");
143
144 pub const DEV_SIGNER: Self = Self::new(hex::decode_const(
151 b"9affcfae47b848ec2caf1c49b4b283531e1cc425f93582b36806e52a43d78d1a",
152 ));
153
154 pub const PROD_SIGNER: Self = Self::new(hex::decode_const(
157 b"02d07f56b7f4a71d32211d6821beaeb316fbf577d02bab0dfe1f18a73de08a8e",
158 ));
159
160 pub const fn expected_signer(use_sgx: bool, is_dev: bool) -> Self {
163 if use_sgx {
164 if is_dev {
165 Self::DEV_SIGNER
166 } else {
167 Self::PROD_SIGNER
168 }
169 } else {
170 Self::MOCK_SIGNER
171 }
172 }
173
174 pub fn compute_from_sgxs(
185 mut sgxs_reader: impl io::Read,
186 ) -> io::Result<Self> {
187 let mut buf = [0u8; 4096];
188 let mut digest = sha256::Context::new();
189
190 loop {
191 let n = sgxs_reader.read(&mut buf)?;
192 if n == 0 {
193 let hash = digest.finish();
194 return Ok(Self::new(hash.to_array()));
195 } else {
196 digest.update(&buf[0..n]);
197 }
198 }
199 }
200
201 pub const fn new(bytes: [u8; 32]) -> Self {
202 Self(bytes)
203 }
204
205 pub fn short(&self) -> MrShort {
206 MrShort::from(self)
207 }
208}
209
210lexe_byte_array::impl_byte_array!(Measurement, 32);
211lexe_byte_array::impl_fromstr_fromhex!(Measurement, 32);
212lexe_byte_array::impl_debug_display_as_hex!(Measurement);
213
214impl MrShort {
217 pub const fn new(bytes: [u8; 4]) -> Self {
218 Self(bytes)
219 }
220
221 pub fn is_prefix_of(&self, long: &Measurement) -> bool {
223 self.0 == long.0[..4]
224 }
225}
226
227lexe_byte_array::impl_byte_array!(MrShort, 4);
228lexe_byte_array::impl_fromstr_fromhex!(MrShort, 4);
229lexe_byte_array::impl_debug_display_as_hex!(MrShort);
230
231impl From<&Measurement> for MrShort {
232 fn from(long: &Measurement) -> Self {
233 (long.0)[..4].try_into().map(Self).unwrap()
234 }
235}
236
237impl MachineId {
240 pub const MOCK: Self =
243 MachineId::new(hex::decode_const(b"52bc575eb9618084083ca7b3a45a2a76"));
244
245 pub const fn new(bytes: [u8; 16]) -> Self {
246 Self(bytes)
247 }
248}
249
250lexe_byte_array::impl_byte_array!(MachineId, 16);
251lexe_byte_array::impl_fromstr_fromhex!(MachineId, 16);
252lexe_byte_array::impl_debug_display_as_hex!(MachineId);
253
254impl<'a> Sealed<'a> {
257 pub const TAG_LEN: usize = 16;
259
260 pub fn serialize(&self) -> Vec<u8> {
261 let out_len = mem::size_of::<u32>()
262 + self.keyrequest.len()
263 + mem::size_of::<u32>()
264 + self.ciphertext.len();
265 let mut out = Vec::with_capacity(out_len);
266
267 out.extend_from_slice(&(self.keyrequest.len() as u32).to_le_bytes());
268 out.extend_from_slice(self.keyrequest.as_ref());
269 out.extend_from_slice(&(self.ciphertext.len() as u32).to_le_bytes());
270 out.extend_from_slice(self.ciphertext.as_ref());
271
272 out
273 }
274
275 pub fn deserialize(bytes: &'a [u8]) -> Result<Self, Error> {
276 let (keyrequest, bytes) = Self::read_bytes(bytes)?;
277 let (ciphertext, bytes) = Self::read_bytes(bytes)?;
278
279 if bytes.is_empty() {
280 Ok(Self {
281 keyrequest: Cow::Borrowed(keyrequest),
282 ciphertext: Cow::Borrowed(ciphertext),
283 })
284 } else {
285 Err(Error::DeserializationError)
286 }
287 }
288
289 fn read_bytes(bytes: &[u8]) -> Result<(&[u8], &[u8]), Error> {
292 let (len, bytes) = Self::read_u32_le(bytes)?;
293 let len = len as usize;
294 if bytes.len() >= len {
295 Ok(bytes.split_at(len))
296 } else {
297 Err(Error::DeserializationError)
298 }
299 }
300
301 fn read_u32_le(bytes: &[u8]) -> Result<(u32, &[u8]), Error> {
304 match bytes.split_first_chunk::<4>() {
305 Some((val, rest)) => Ok((u32::from_le_bytes(*val), rest)),
306 None => Err(Error::DeserializationError),
307 }
308 }
309}
310
311impl fmt::Debug for Sealed<'_> {
312 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
313 f.debug_struct("Sealed")
314 .field("keyrequest", &hex::display(&self.keyrequest))
315 .field("ciphertext", &hex::display(&self.ciphertext))
316 .finish()
317 }
318}
319
320impl MinCpusvn {
323 pub const CURRENT: Self =
327 Self::new(hex::decode_const(b"0e0e100fffff01000000000000000000"));
328
329 pub const fn new(bytes: [u8; 16]) -> Self {
330 Self(bytes)
331 }
332
333 pub const fn to_array(self) -> [u8; 16] {
334 self.0
335 }
336}
337
338pub mod attributes {
368 use sgx_isa::AttributesFlags;
369
370 pub const LEXE_FLAGS_PROD: AttributesFlags = AttributesFlags::MODE64BIT;
374
375 pub const LEXE_FLAGS_DEBUG: AttributesFlags =
376 LEXE_FLAGS_PROD.union(AttributesFlags::DEBUG);
377
378 pub const LEXE_MASK: AttributesFlags = AttributesFlags::INIT
380 .union(AttributesFlags::DEBUG)
381 .union(AttributesFlags::MODE64BIT);
382}
383
384pub mod xfrm {
388 pub const LEGACY: u64 = 0x0000000000000003;
391 pub const AVX: u64 = 0x0000000000000006;
394 pub const AVX512: u64 = 0x00000000000000e6;
396 pub const MPX: u64 = 0x0000000000000018;
398 pub const PKRU: u64 = 0x0000000000000200;
400 pub const AMX: u64 = 0x0000000000060000;
402
403 pub const LEXE_FLAGS: u64 = AVX512 | LEGACY;
412
413 pub const LEXE_MASK: u64 = LEXE_FLAGS;
415}
416
417pub mod miscselect {
419 use sgx_isa::Miscselect;
420
421 pub const LEXE_FLAGS: Miscselect = Miscselect::empty();
423
424 pub const LEXE_MASK: Miscselect = Miscselect::empty();
426}
427
428#[cfg(test)]
429mod test {
430 use std::str::FromStr;
431
432 use proptest::{arbitrary::any, proptest, strategy::Strategy};
433 use serde_core::{de::DeserializeOwned, ser::Serialize};
434
435 use super::*;
436
437 #[track_caller]
438 fn json_string_roundtrip<
439 T: DeserializeOwned + Serialize + PartialEq + fmt::Debug,
440 >(
441 s1: &str,
442 ) {
443 let x1: T = serde_json::from_str(s1).unwrap();
444 let s2 = serde_json::to_string(&x1).unwrap();
445 let x2: T = serde_json::from_str(&s2).unwrap();
446 assert_eq!(x1, x2);
447 assert_eq!(s1, s2);
448 }
449
450 #[track_caller]
451 fn fromstr_display_roundtrip<
452 T: FromStr + fmt::Display + PartialEq + fmt::Debug,
453 >(
454 s1: &str,
455 ) {
456 let x1 = T::from_str(s1).map_err(|_| ()).unwrap();
457 let s2 = x1.to_string();
458 let x2 = T::from_str(&s2).map_err(|_| ()).unwrap();
459 assert_eq!(x1, x2);
460 assert_eq!(s1, s2);
461 }
462
463 #[test]
464 fn serde_roundtrips() {
465 json_string_roundtrip::<Measurement>(
466 "\"c4f249b8d3121b0e61170a93a526beda574058f782c0b3f339e74651c379f888\"",
467 );
468 json_string_roundtrip::<MachineId>(
469 "\"df3d290e1371112bd3da4a6cdda1f245\"",
470 );
471 }
472
473 #[test]
474 fn fromstr_display_roundtrips() {
475 fromstr_display_roundtrip::<Measurement>(
476 "c4f249b8d3121b0e61170a93a526beda574058f782c0b3f339e74651c379f888",
477 );
478 fromstr_display_roundtrip::<MachineId>(
479 "df3d290e1371112bd3da4a6cdda1f245",
480 );
481 }
482
483 #[test]
484 fn test_mr_short() {
485 proptest!(|(
486 long1 in any::<Measurement>(),
487 long2 in any::<Measurement>(),
488 )| {
489 let short1 = long1.short();
490 let short2 = long2.short();
491 assert!(short1.is_prefix_of(&long1));
492 assert!(short2.is_prefix_of(&long2));
493
494 if short1 != short2 {
495 assert_ne!(long1, long2);
496 assert!(!short1.is_prefix_of(&long2));
497 assert!(!short2.is_prefix_of(&long1));
498 }
499 });
500 }
501
502 #[test]
503 fn test_sealed_serialization() {
504 let arb_keyrequest = any::<Vec<u8>>();
505 let arb_ciphertext = any::<Vec<u8>>();
506 let arb_sealed = (arb_keyrequest, arb_ciphertext).prop_map(
507 |(keyrequest, ciphertext)| Sealed {
508 keyrequest: keyrequest.into(),
509 ciphertext: ciphertext.into(),
510 },
511 );
512
513 proptest!(|(sealed in arb_sealed)| {
514 let bytes = sealed.serialize();
515 let sealed2 = Sealed::deserialize(&bytes).unwrap();
516 assert_eq!(sealed, sealed2);
517 });
518 }
519}