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