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