Skip to main content

sgx_isa/
lib.rs

1/* Copyright (c) Jethro G. Beekman and Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6//! Constants and structures related to the Intel SGX ISA extension.
7//!
8//! These are taken directly from the [Intel Software Developer's Manual][isdm],
9//! volume 3, chapters 37–43. Rust conversions traits were added where
10//! convenient.
11//!
12//! [isdm]: https://www-ssl.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
13#![no_std]
14#![doc(
15    html_logo_url = "https://edp.fortanix.com/img/docs/edp-logo.svg",
16    html_favicon_url = "https://edp.fortanix.com/favicon.ico",
17    html_root_url = "https://edp.fortanix.com/docs/api/"
18)]
19#![cfg_attr(all(feature = "sgxstd", target_env = "sgx"), feature(sgx_platform))]
20
21#[cfg(all(feature = "sgxstd", target_env = "sgx"))]
22extern crate std;
23
24#[macro_use]
25extern crate bitflags;
26
27#[cfg(feature = "serde")]
28extern crate serde;
29
30#[cfg(feature = "serde")]
31use serde::{Deserialize, Serialize};
32
33#[cfg(target_env = "sgx")]
34mod arch;
35
36use core::slice;
37
38#[cfg(target_env = "sgx")]
39use core::convert::TryFrom;
40
41#[cfg(feature = "serde")]
42mod array_64 {
43    use core::fmt;
44    use serde::{
45        de::{Deserializer, Error, SeqAccess, Visitor},
46        ser::{SerializeTuple, Serializer},
47    };
48
49    const LEN: usize = 64;
50
51    pub fn serialize<S: Serializer>(array: &[u8; LEN], serializer: S) -> Result<S::Ok, S::Error> {
52        let mut seq = serializer.serialize_tuple(LEN)?;
53        for elem in &array[..] {
54            seq.serialize_element(elem)?;
55        }
56        seq.end()
57    }
58
59    pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<[u8; LEN], D::Error> {
60        struct ArrayVisitor;
61        impl<'de> Visitor<'de> for ArrayVisitor {
62            type Value = [u8; LEN];
63            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
64                write!(formatter, "an array of length 64")
65            }
66            fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<[u8; LEN], A::Error> {
67                let mut arr = [0; LEN];
68                for i in 0..LEN {
69                    arr[i] = seq
70                        .next_element()?
71                        .ok_or_else(|| A::Error::invalid_length(i, &self))?;
72                }
73                Ok(arr)
74            }
75        }
76        deserializer.deserialize_tuple(64, ArrayVisitor)
77    }
78}
79
80// These helper functions implement defaults for structs' reserved fields,
81// which is necessary for serde support.
82#[cfg(feature = "serde")]
83fn report_reserved4() -> [u8; 42] {
84    [0u8; 42]
85}
86
87#[cfg(feature = "serde")]
88fn ti_reserved1() -> [u8; 4] {
89    [0u8; 4]
90}
91
92#[cfg(feature = "serde")]
93fn ti_reserved2() -> [u8; 456] {
94    [0u8; 456]
95}
96
97#[cfg(not(feature = "large_array_derive"))]
98#[macro_use]
99mod large_array_impl;
100#[cfg(feature = "large_array_derive")]
101macro_rules! impl_default_clone_eq {
102    ($n:ident) => {};
103}
104
105pub mod tdx;
106
107#[macro_export]
108macro_rules! enum_def {
109    (
110        #[derive($($derive:meta),*)]
111        #[repr($repr:ident)]
112        pub enum $name:ident {
113            $($key:ident = $val:expr,)*
114        }
115    ) => (
116        #[derive($($derive),*)]
117        #[repr($repr)]
118        pub enum $name {
119            $($key = $val,)*
120        }
121
122        impl core::convert::TryFrom<$repr> for $name {
123            type Error = core::num::TryFromIntError;
124            fn try_from(v: $repr) -> Result<Self, Self::Error> {
125                match v {
126                    $($val => Ok($name::$key),)*
127                    _ => Err(u8::try_from(256u16).unwrap_err()),
128                }
129            }
130        }
131    )
132}
133
134#[macro_export]
135macro_rules! struct_def {
136    (
137        $(#[doc = $doc:expr])*
138        #[repr(C $(, align($align:tt))*)]
139        $(#[cfg_attr(feature = "large_array_derive", derive($($cfgderive:meta),*))])*
140        $(#[cfg_attr(feature = "serde", derive($($serdederive:meta),*))])*
141        $(#[derive($($derive:meta),*)])*
142        pub struct $name:ident $impl:tt
143    ) => {
144        $(
145            impl_default_clone_eq!($name);
146            #[cfg_attr(feature = "large_array_derive", derive($($cfgderive),*))]
147        )*
148        #[repr(C $(, align($align))*)]
149        $(#[cfg_attr(feature = "serde", derive($($serdederive),*))])*
150        $(#[derive($($derive),*)])*
151        $(#[doc = $doc])*
152        pub struct $name $impl
153
154        impl $name {
155            /// If `src` has the correct length for this type, returns `Some<T>`
156            /// copied from `src`, else returns `None`.
157            pub fn try_copy_from(src: &[u8]) -> Option<Self> {
158                if src.len() == Self::UNPADDED_SIZE {
159                    unsafe {
160                        let mut ret : Self = ::core::mem::zeroed();
161                        ::core::ptr::copy_nonoverlapping(src.as_ptr(),
162                                                         &mut ret as *mut _ as *mut _,
163                                                         Self::UNPADDED_SIZE);
164                        Some(ret)
165                    }
166                } else {
167                    None
168                }
169            }
170
171            // Compile time check that the size argument is correct.
172            // Not otherwise used.
173            fn _type_tests() {
174                #[repr(C)]
175                $(#[cfg_attr(feature = "serde", derive($($serdederive),*))])*
176                struct _Unaligned $impl
177
178                impl _Unaligned {
179                    unsafe fn _check_size(self) -> [u8; $name::UNPADDED_SIZE] {
180                        ::core::mem::transmute(self)
181                    }
182                }
183
184                // Should also check packed size against unaligned size here,
185                // but Rust doesn't allow packed structs to contain aligned
186                // structs, so this can't be tested.
187            }
188        }
189
190        $(
191        // check that alignment is set correctly
192        #[test]
193        #[allow(non_snake_case)]
194        fn $name() {
195            assert_eq!($align, ::core::mem::align_of::<$name>());
196        }
197        )*
198
199        impl AsRef<[u8]> for $name {
200            fn as_ref(&self) -> &[u8] {
201                unsafe {
202                    slice::from_raw_parts(self as *const $name as *const u8, Self::UNPADDED_SIZE)
203                }
204            }
205        }
206
207        struct_def!(@align bytes $($align)* name $name);
208    };
209    (@align bytes 16 name $name:ident) => {
210        struct_def!(@align type Align16 name $name);
211    };
212    (@align bytes 128 name $name:ident) => {
213        struct_def!(@align type Align128 name $name);
214    };
215    (@align bytes 256 name $name:ident) => {
216        struct_def!(@align type Align256 name $name);
217    };
218    (@align bytes 512 name $name:ident) => {
219        struct_def!(@align type Align512 name $name);
220    };
221    (@align bytes $($other:tt)*) => {};
222    (@align type $ty:ident name $name:ident) => {
223        #[cfg(target_env = "sgx")]
224        impl AsRef<arch::$ty<[u8; $name::UNPADDED_SIZE]>> for $name {
225            fn as_ref(&self) -> &arch::$ty<[u8; $name::UNPADDED_SIZE]> {
226                unsafe {
227                    &*(self as *const _ as *const _)
228                }
229            }
230        }
231    };
232}
233
234enum_def! {
235#[derive(Clone,Copy,Debug,PartialEq,Eq)]
236#[repr(u32)]
237pub enum Encls {
238    ECreate =  0,
239    EAdd    =  1,
240    EInit   =  2,
241    ERemove =  3,
242    EDbgrd  =  4,
243    EDbgwr  =  5,
244    EExtend =  6,
245    ELdb    =  7,
246    ELdu    =  8,
247    EBlock  =  9,
248    EPa     = 10,
249    EWb     = 11,
250    ETrack  = 12,
251    EAug    = 13,
252    EModpr  = 14,
253    EModt   = 15,
254}
255}
256
257enum_def! {
258#[derive(Clone,Copy,Debug,PartialEq,Eq)]
259#[repr(u32)]
260pub enum Enclu {
261    EReport        = 0,
262    EGetkey        = 1,
263    EEnter         = 2,
264    EResume        = 3,
265    EExit          = 4,
266    EAccept        = 5,
267    EModpe         = 6,
268    EAcceptcopy    = 7,
269    EVerifyReport2 = 8,
270}
271}
272
273enum_def! {
274#[derive(Clone,Copy,Debug,PartialEq,Eq)]
275#[repr(u32)]
276pub enum ErrorCode {
277    Success                =   0,
278    InvalidSigStruct       =   1,
279    InvalidAttribute       =   2,
280    Blkstate               =   3, // Blstate in §40.1.4, Blkstate in §40.3
281    InvalidMeasurement     =   4,
282    Notblockable           =   5,
283    PgInvld                =   6,
284    Lockfail               =   7,
285    InvalidSignature       =   8,
286    MacCompareFail         =   9,
287    PageNotBlocked         =  10,
288    NotTracked             =  11,
289    VaSlotOccupied         =  12,
290    ChildPresent           =  13,
291    EnclaveAct             =  14,
292    EntryepochLocked       =  15,
293    InvalidEinitToken      =  16,
294    PrevTrkIncmpl          =  17,
295    PgIsSecs               =  18,
296    PageAttributesMismatch =  19,
297    PageNotModifiable      =  20,
298    PageNotDebuggable      =  21,
299    InvalidReportMacStruct =  28,
300    InvalidCpusvn          =  32,
301    InvalidIsvsvn          =  64,
302    UnmaskedEvent          = 128,
303    InvalidKeyname         = 256,
304}
305}
306
307pub const MEAS_ECREATE: u64 = 0x0045544145524345;
308pub const MEAS_EADD: u64 = 0x0000000044444145;
309pub const MEAS_EEXTEND: u64 = 0x00444E4554584545;
310
311pub const SIGSTRUCT_HEADER1: [u8; 16] = [
312    0x06, 0x00, 0x00, 0x00, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
313];
314pub const SIGSTRUCT_HEADER2: [u8; 16] = [
315    0x01, 0x01, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
316];
317
318enum_def! {
319#[derive(Clone,Copy,Debug,PartialEq,Eq)]
320#[repr(u8)]
321pub enum PageType {
322    Secs = 0,
323    Tcs  = 1,
324    Reg  = 2,
325    Va   = 3,
326    Trim = 4,
327}
328}
329
330enum_def! {
331#[derive(Clone,Copy,Debug,PartialEq,Eq)]
332#[repr(u16)]
333pub enum Keyname {
334    Einittoken    = 0,
335    Provision     = 1,
336    ProvisionSeal = 2,
337    Report        = 3,
338    Seal          = 4,
339}
340}
341
342struct_def! {
343#[repr(C, align(4096))]
344#[cfg_attr(
345    feature = "large_array_derive",
346    derive(Clone, Debug, Default, Eq, PartialEq)
347)]
348pub struct Secs {
349    pub size: u64,
350    pub baseaddr: u64,
351    pub ssaframesize: u32,
352    pub miscselect: Miscselect,
353    pub _reserved1: [u8; 24],
354    pub attributes: Attributes,
355    pub mrenclave: [u8; 32],
356    pub _reserved2: [u8; 32],
357    pub mrsigner: [u8; 32],
358    pub _reserved3: [u8; 96],
359    pub isvprodid: u16,
360    pub isvsvn: u16,
361    pub padding: [u8; 3836],
362}
363}
364
365impl Secs {
366    pub const UNPADDED_SIZE: usize = 4096;
367}
368
369struct_def! {
370#[repr(C)]
371#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
372#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
373pub struct Attributes {
374    pub flags: AttributesFlags,
375    pub xfrm: u64,
376}
377}
378
379impl Attributes {
380    pub const UNPADDED_SIZE: usize = 16;
381}
382
383bitflags! {
384    #[repr(C)]
385    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
386    pub struct AttributesFlags: u64 {
387        const INIT          = 0b0000_0001;
388        const DEBUG         = 0b0000_0010;
389        const MODE64BIT     = 0b0000_0100;
390        const PROVISIONKEY  = 0b0001_0000;
391        const EINITTOKENKEY = 0b0010_0000;
392        const CET           = 0b0100_0000;
393        const KSS           = 0b1000_0000;
394    }
395}
396
397impl Default for AttributesFlags {
398    fn default() -> Self {
399        Self::empty()
400    }
401}
402
403bitflags! {
404    #[repr(C)]
405    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
406    pub struct Miscselect: u32 {
407        const EXINFO = 0b0000_0001;
408    }
409}
410
411impl Default for Miscselect {
412    fn default() -> Self {
413        Self::empty()
414    }
415}
416
417struct_def! {
418#[repr(C, align(4096))]
419#[cfg_attr(
420    feature = "large_array_derive",
421    derive(Clone, Debug, Default, Eq, PartialEq)
422)]
423pub struct Tcs {
424    pub _reserved1: u64,
425    pub flags: TcsFlags,
426    pub ossa: u64,
427    pub cssa: u32,
428    pub nssa: u32,
429    pub oentry: u64,
430    pub _reserved2: u64,
431    pub ofsbasgx: u64,
432    pub ogsbasgx: u64,
433    pub fslimit: u32,
434    pub gslimit: u32,
435    pub _reserved3: [u8; 4024],
436}
437}
438
439impl Tcs {
440    pub const UNPADDED_SIZE: usize = 4096;
441}
442
443bitflags! {
444    #[repr(C)]
445    pub struct TcsFlags: u64 {
446        const DBGOPTIN = 0b0000_0001;
447    }
448}
449
450impl Default for TcsFlags {
451    fn default() -> Self {
452        Self::empty()
453    }
454}
455
456struct_def! {
457#[repr(C, align(32))]
458#[derive(Clone, Debug, Default, Eq, PartialEq)]
459pub struct Pageinfo {
460    pub linaddr: u64,
461    pub srcpge: u64,
462    pub secinfo: u64,
463    pub secs: u64,
464}
465}
466
467impl Pageinfo {
468    pub const UNPADDED_SIZE: usize = 32;
469}
470
471struct_def! {
472#[repr(C, align(64))]
473#[cfg_attr(
474    feature = "large_array_derive",
475    derive(Clone, Debug, Default, Eq, PartialEq)
476)]
477pub struct Secinfo {
478    pub flags: SecinfoFlags,
479    pub _reserved1: [u8; 56],
480}
481}
482
483impl Secinfo {
484    pub const UNPADDED_SIZE: usize = 64;
485}
486
487bitflags! {
488    #[repr(C)]
489    pub struct SecinfoFlags: u64 {
490        const R        = 0b0000_0000_0000_0001;
491        const W        = 0b0000_0000_0000_0010;
492        const X        = 0b0000_0000_0000_0100;
493        const PENDING  = 0b0000_0000_0000_1000;
494        const MODIFIED = 0b0000_0000_0001_0000;
495        const PR       = 0b0000_0000_0010_0000;
496        const PT_MASK  = 0b1111_1111_0000_0000;
497        const PT_B0    = 0b0000_0001_0000_0000; // ****
498        const PT_B1    = 0b0000_0010_0000_0000; // * These are just here so
499        const PT_B2    = 0b0000_0100_0000_0000; // * that something shows
500        const PT_B3    = 0b0000_1000_0000_0000; // * up in the Debug output
501        const PT_B4    = 0b0001_0000_0000_0000; // *
502        const PT_B5    = 0b0010_0000_0000_0000; // *
503        const PT_B6    = 0b0100_0000_0000_0000; // *
504        const PT_B7    = 0b1000_0000_0000_0000; // ****
505    }
506}
507
508impl Default for SecinfoFlags {
509    fn default() -> Self {
510        Self::empty()
511    }
512}
513
514impl SecinfoFlags {
515    pub fn page_type(&self) -> u8 {
516        (((*self & SecinfoFlags::PT_MASK).bits) >> 8) as u8
517    }
518
519    pub fn page_type_mut(&mut self) -> &mut u8 {
520        use core::mem::transmute;
521        unsafe {
522            let page_type: &mut [u8; 8] = transmute(&mut self.bits);
523            transmute(&mut page_type[1])
524        }
525    }
526}
527
528impl From<PageType> for SecinfoFlags {
529    fn from(data: PageType) -> SecinfoFlags {
530        SecinfoFlags::from_bits_truncate((data as u64) << 8)
531    }
532}
533
534struct_def! {
535#[repr(C, align(128))]
536#[cfg_attr(
537    feature = "large_array_derive",
538    derive(Clone, Debug, Default, Eq, PartialEq)
539)]
540pub struct Pcmd {
541    pub secinfo: Secinfo,
542    pub enclaveid: u64,
543    pub _reserved1: [u8; 40],
544    pub mac: [u8; 16],
545}
546}
547
548impl Pcmd {
549    pub const UNPADDED_SIZE: usize = 128;
550}
551
552struct_def! {
553#[repr(C, align(4096))]
554#[cfg_attr(
555    feature = "large_array_derive",
556    derive(Clone, Debug, Default, Eq, PartialEq)
557)]
558pub struct Sigstruct {
559    pub header: [u8; 16],
560    pub vendor: u32,
561    pub date: u32,
562    pub header2: [u8; 16],
563    pub swdefined: u32,
564    pub _reserved1: [u8; 84],
565    pub modulus: [u8; 384],
566    pub exponent: u32,
567    pub signature: [u8; 384],
568    pub miscselect: Miscselect,
569    pub miscmask: u32,
570    pub cet_attributes: u8,
571    pub cet_attributes_mask: u8,
572    pub _reserved2: u16,
573    pub isvfamilyid: [u8; 16],
574    pub attributes: Attributes,
575    pub attributemask: [u64; 2],
576    pub enclavehash: [u8; 32],
577    pub _reserved3: [u8; 16],
578    pub isvextprodid: [u8; 16],
579    pub isvprodid: u16,
580    pub isvsvn: u16,
581    pub _reserved4: [u8; 12],
582    pub q1: [u8; 384],
583    pub q2: [u8; 384],
584}
585}
586
587impl Sigstruct {
588    pub const UNPADDED_SIZE: usize = 1808;
589
590    /// Returns that part of the `Sigstruct` that is signed. The returned
591    /// slices should be concatenated for hashing.
592    pub fn signature_data(&self) -> (&[u8], &[u8]) {
593        unsafe {
594            let part1_start = &(self.header) as *const _ as *const u8;
595            let part1_end = &(self.modulus) as *const _ as *const u8 as usize;
596            let part2_start = &(self.miscselect) as *const _ as *const u8;
597            let part2_end = &(self._reserved4) as *const _ as *const u8 as usize;
598
599            (
600                slice::from_raw_parts(part1_start, part1_end - (part1_start as usize)),
601                slice::from_raw_parts(part2_start, part2_end - (part2_start as usize)),
602            )
603        }
604    }
605}
606
607struct_def! {
608#[repr(C, align(512))]
609#[cfg_attr(
610    feature = "large_array_derive",
611    derive(Clone, Debug, Default, Eq, PartialEq)
612)]
613pub struct Einittoken {
614    pub valid: u32,
615    pub _reserved1: [u8; 44],
616    pub attributes: Attributes,
617    pub mrenclave: [u8; 32],
618    pub _reserved2: [u8; 32],
619    pub mrsigner: [u8; 32],
620    pub _reserved3: [u8; 32],
621    pub cpusvnle: [u8; 16],
622    pub isvprodidle: u16,
623    pub isvsvnle: u16,
624    pub _reserved4: [u8; 24],
625    pub maskedmiscselectle: Miscselect,
626    pub maskedattributesle: Attributes,
627    pub keyid: [u8; 32],
628    pub mac: [u8; 16],
629}
630}
631
632impl Einittoken {
633    pub const UNPADDED_SIZE: usize = 304;
634}
635
636struct_def! {
637#[repr(C, align(512))]
638#[cfg_attr(
639    feature = "large_array_derive",
640    derive(Clone, Debug, Default, Eq, PartialEq)
641)]
642#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
643pub struct Report {
644    pub cpusvn: [u8; 16],
645    pub miscselect: Miscselect,
646    pub cet_attributes: u8,
647    #[cfg_attr(feature = "serde", serde(skip))]
648    pub _reserved1: [u8; 11],
649    pub isvextnprodid: [u8; 16],
650    pub attributes: Attributes,
651    pub mrenclave: [u8; 32],
652    #[cfg_attr(feature = "serde", serde(skip))]
653    pub _reserved2: [u8; 32],
654    pub mrsigner: [u8; 32],
655    #[cfg_attr(feature = "serde", serde(skip))]
656    pub _reserved3: [u8; 32],
657    #[cfg_attr(feature = "serde", serde(with = "array_64"))]
658    pub configid: [u8; 64],
659    pub isvprodid: u16,
660    pub isvsvn: u16,
661    pub configsvn: u16,
662    #[cfg_attr(feature = "serde", serde(default = "report_reserved4"), serde(skip))]
663    pub _reserved4: [u8; 42],
664    pub isvfamilyid: [u8; 16],
665    #[cfg_attr(feature = "serde", serde(with = "array_64"))]
666    pub reportdata: [u8; 64],
667    pub keyid: [u8; 32],
668    pub mac: [u8; 16],
669}
670}
671
672impl Report {
673    pub const UNPADDED_SIZE: usize = 432;
674    /// Report size without keyid and mac
675    pub const TRUNCATED_SIZE: usize = 384;
676
677    /// Generate a bogus report that can be used to obtain one's own
678    /// `Targetinfo`.
679    ///
680    /// # Examples
681    /// ```
682    /// use sgx_isa::{Report, Targetinfo};
683    ///
684    /// let targetinfo_self = Targetinfo::from(Report::for_self());
685    /// ```
686    #[cfg(target_env = "sgx")]
687    pub fn for_self() -> Self {
688        let reportdata = arch::Align128([0; 64]);
689        let targetinfo = arch::Align512([0; 512]);
690        let out = arch::ereport(&targetinfo, &reportdata);
691        // unwrap ok, `out` is the correct number of bytes
692        Report::try_copy_from(&out.0).unwrap()
693    }
694
695    #[cfg(target_env = "sgx")]
696    pub fn for_target(targetinfo: &Targetinfo, reportdata: &[u8; 64]) -> Report {
697        let reportdata = arch::Align128(*reportdata);
698        let out = arch::ereport(targetinfo.as_ref(), &reportdata);
699        // unwrap ok, `out` is the correct number of bytes
700        Report::try_copy_from(&out.0).unwrap()
701    }
702
703    /// This function verifies the report's MAC using the provided
704    /// implementation of the verifying function.
705    ///
706    /// Care should be taken that `check_mac` prevents timing attacks,
707    /// in particular that the comparison happens in constant time.
708    #[cfg(target_env = "sgx")]
709    pub fn verify<F, R>(&self, check_mac: F) -> R
710    where
711        F: FnOnce(&[u8; 16], &[u8; Report::TRUNCATED_SIZE], &[u8; 16]) -> R,
712    {
713        let req = Keyrequest {
714            keyname: Keyname::Report as u16,
715            keyid: self.keyid,
716            ..Default::default()
717        };
718        let key = req.egetkey().expect("Couldn't get report key");
719        check_mac(&key, self.mac_data(), &self.mac)
720    }
721
722    /// Returns that part of the `Report` that is MACed.
723    pub fn mac_data(&self) -> &[u8; Report::TRUNCATED_SIZE] {
724        unsafe { &*(self as *const Self as *const [u8; Report::TRUNCATED_SIZE]) }
725    }
726}
727
728struct_def! {
729#[repr(C, align(512))]
730#[cfg_attr(
731    feature = "large_array_derive",
732    derive(Clone, Debug, Default, Eq, PartialEq)
733)]
734#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
735pub struct Targetinfo {
736    pub measurement: [u8; 32],
737    pub attributes: Attributes,
738    #[cfg_attr(feature = "serde", serde(default = "ti_reserved1"), serde(skip))]
739    pub _reserved1: [u8; 4],
740    pub miscselect: Miscselect,
741    #[cfg_attr(feature = "serde", serde(default = "ti_reserved2"), serde(skip))]
742    pub _reserved2: [u8; 456],
743}
744}
745
746impl Targetinfo {
747    pub const UNPADDED_SIZE: usize = 512;
748}
749
750impl From<Report> for Targetinfo {
751    fn from(r: Report) -> Targetinfo {
752        Targetinfo {
753            measurement: r.mrenclave,
754            attributes: r.attributes,
755            miscselect: r.miscselect,
756            ..Targetinfo::default()
757        }
758    }
759}
760
761struct_def! {
762#[repr(C, align(512))]
763#[cfg_attr(
764    feature = "large_array_derive",
765    derive(Clone, Debug, Default, Eq, PartialEq)
766)]
767pub struct Keyrequest {
768    pub keyname: u16,
769    pub keypolicy: Keypolicy,
770    pub isvsvn: u16,
771    pub _reserved1: u16,
772    pub cpusvn: [u8; 16],
773    pub attributemask: [u64; 2],
774    pub keyid: [u8; 32],
775    pub miscmask: u32,
776    pub _reserved2: [u8; 436],
777}
778}
779
780impl Keyrequest {
781    pub const UNPADDED_SIZE: usize = 512;
782
783    #[cfg(target_env = "sgx")]
784    pub fn egetkey(&self) -> Result<[u8; 16], ErrorCode> {
785        match arch::egetkey(self.as_ref()) {
786            Ok(k) => Ok(k.0),
787            // unwrap ok, `arch::egetkey` will always return a valid `ErrorCode`
788            Err(e) => Err(ErrorCode::try_from(e).unwrap()),
789        }
790    }
791}
792
793bitflags! {
794    #[repr(C)]
795    pub struct Keypolicy: u16 {
796        const MRENCLAVE = 0b0000_0001;
797        const MRSIGNER  = 0b0000_0010;
798    }
799}
800
801impl Default for Keypolicy {
802    fn default() -> Self {
803        Self::empty()
804    }
805}
806
807struct_def! {
808    /// Rust definition of `REPORTTYPE` from `REPORTMACSTRUCT`.
809    ///
810    /// Ref: Intel® Trust Domain CPU Architectural Extensions, table 2-4.
811    /// Version: 343754-002US, MAY 2021
812    /// Link: <https://cdrdv2.intel.com/v1/dl/getContent/733582>
813    #[repr(C, align(4))]
814    #[derive(Clone, Debug, Default, Eq, PartialEq)]
815    pub struct ReportType {
816        /// Trusted Execution Environment(TEE) type:
817        ///   0x00:      SGX Legacy REPORT TYPE
818        ///   0x7F-0x01: Reserved
819        ///   0x80:      Reserved
820        ///   0x81:      TEE Report type 2
821        ///   0xFF-0x82: Reserved
822        pub report_type: u8,
823        /// TYPE-specific subtype, Stage1: value is 0
824        pub subtype: u8,
825        /// TYPE-specific version, Stage1: value is 0
826        pub version: u8,
827        pub reserved: u8,
828    }
829}
830
831impl ReportType {
832    pub const UNPADDED_SIZE: usize = 4;
833}
834
835// All variants of ReportVersion that is valid for TDX report
836enum_def! {
837#[derive(Clone,Copy,Debug,PartialEq,Eq)]
838#[repr(u8)]
839pub enum ReportTypeType {
840    Sgx = 0x00,
841    // 0x01 - 0x7F - Reserved for processor-based TEE report
842    // 0x80 - Reserved for SEAM-based TEE report
843    Tdx = 0x81,
844    // 0x82 - 0xFF - Reserved for SEAM-based TEE report
845}
846}
847
848/// SHA384 hash size in bytes
849pub const HASH_384_SIZE: usize = 48;
850/// SHA384 hash
851pub type Sha384Hash = [u8; HASH_384_SIZE];
852
853pub const CPU_SVN_SIZE: usize = 16;
854pub const REPORT_MAC_STRUCT_SIZE: usize = 256;
855pub const REPORT_MAC_STRUCT_RESERVED1_BYTES: usize = 12;
856pub const REPORT_MAC_STRUCT_RESERVED2_BYTES: usize = 32;
857pub const REPORT_DATA_SIZE: usize = 64;
858
859/// Message SHA 256 HASH Code - 32 bytes
860pub const TEE_MAC_SIZE: usize = 32;
861
862struct_def! {
863/// Rust definition of `REPORTMACSTRUCT`, used by TDX `TDREPORT_STRUCT`
864/// and the future 256BITSGX
865///
866/// Ref: Intel® Trust Domain CPU Architectural Extensions, table 2-5.
867/// Version: 343754-002US, MAY 2021
868/// Link TDX: <https://cdrdv2.intel.com/v1/dl/getContent/733582>
869/// Link 256BITSGX: <https://cdrdv2-public.intel.com/851355/319433-057-architecture-instruction-set-extensions-programming-reference.pdf>
870#[repr(C, align(256))]
871#[cfg_attr(
872    feature = "large_array_derive",
873    derive(Clone, Debug, Default, Eq, PartialEq)
874)]
875pub struct ReportMacStruct {
876    /// (  0) TEE Report type
877    pub report_type: ReportType,
878    /// (  4) Reserved, must be zero
879    pub _reserved1: [u8; REPORT_MAC_STRUCT_RESERVED1_BYTES],
880    /// ( 16) Security Version of the CPU
881    pub cpusvn: [u8; CPU_SVN_SIZE],
882    /// ( 32) SHA384 of TEE_TCB_INFO for TEEs
883    pub tee_tcb_info_hash: Sha384Hash,
884    /// ( 80) SHA384 of TEE_INFO
885    pub tee_info_hash: Sha384Hash,
886    /// (128) Data provided by the user
887    pub report_data: [u8; REPORT_DATA_SIZE],
888    /// (192) Reserved, must be zero
889    pub _reserved2: [u8; REPORT_MAC_STRUCT_RESERVED2_BYTES],
890    /// (224) The Message Authentication Code over this structure
891    pub mac: [u8; TEE_MAC_SIZE],
892}
893}
894
895impl ReportMacStruct {
896    pub const UNPADDED_SIZE: usize = 256;
897
898    #[cfg(target_env = "sgx")]
899    pub fn verify(&self) -> Result<(), ErrorCode> {
900        arch::everifyreport2(self.as_ref())
901            // Same as `egetkey` reasoning: unwrap is okay here
902            .map_err(|e| ErrorCode::try_from(e).unwrap())
903    }
904}
905
906#[test]
907fn test_eq() {
908    let mut a = Keyrequest::default();
909    let mut b = Keyrequest::default();
910    assert!(a == b);
911
912    a.keyname = 22;
913    assert!(a != b);
914
915    b.keyname = 22;
916    assert!(a == b);
917
918    a.miscmask = 0xdeadbeef;
919    assert!(a != b);
920
921    b.miscmask = 0xdeadbeef;
922    assert!(a == b);
923}