Skip to main content

csv_rs/api/guest/
types.rs

1// Copyright (C) Hygon Info Technologies Ltd.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6use crate::api::guest::CSV_RTMR_REG_SIZE;
7use crate::error::*;
8use crate::{
9    certs::{csv::Certificate, Usage, Verifiable},
10    crypto::{sig::ecdsa, PublicKey, Signature},
11    util::*,
12};
13
14use openssl::{
15    hash::{Hasher, MessageDigest},
16    pkey, sign,
17};
18
19use static_assertions::const_assert;
20
21use serde::{Deserialize, Serialize};
22use serde_big_array::BigArray;
23use std::io::Write;
24
25use bitfield::bitfield;
26
27pub const ATTESTATION_EXT_MAGIC: [u8; 16] = *b"ATTESTATION_EXT\0";
28
29/// Data provieded by the guest owner for requesting an attestation report
30/// from the HYGON Secure Processor.
31#[repr(C)]
32#[derive(PartialEq, Debug)]
33pub struct ReportReq {
34    /// Guest-provided data to be included in the attestation report
35    pub data: [u8; 64],
36    /// Guest-provided mnonce to be placed in the report to provide protection
37    pub mnonce: [u8; 16],
38    /// hash of [`data`] and [`mnonce`] to provide protection
39    pub hash: [u8; 32],
40}
41
42impl Default for ReportReq {
43    fn default() -> Self {
44        Self {
45            data: [0; 64],
46            mnonce: [0; 16],
47            hash: [0; 32],
48        }
49    }
50}
51
52impl ReportReq {
53    pub fn new(data: Option<[u8; 64]>, mnonce: [u8; 16]) -> Result<Self, Error> {
54        let mut request = Self::default();
55
56        if let Some(data) = data {
57            request.data = data;
58        }
59
60        request.mnonce = mnonce;
61
62        request.calculate_hash()?;
63
64        Ok(request)
65    }
66
67    fn calculate_hash(&mut self) -> Result<(), Error> {
68        let mut hasher = Hasher::new(MessageDigest::sm3())?;
69        hasher.update(self.data.as_ref())?;
70        hasher.update(self.mnonce.as_ref())?;
71        let hash = &hasher.finish()?;
72        self.hash.copy_from_slice(hash.as_ref());
73
74        Ok(())
75    }
76}
77
78/// Data provieded by the guest owner for requesting an extended attestation
79/// report from the HYGON Secure Processor.
80#[repr(C)]
81#[derive(PartialEq, Debug)]
82pub struct ReportReqExt {
83    /// Guest-provided data to be included in the attestation report
84    pub data: [u8; 64],
85    /// Guest-provided mnonce to be placed in the report to provide protection
86    pub mnonce: [u8; 16],
87    /// hash of [`data`] and [`mnonce`] to provide protection
88    pub hash: [u8; 32],
89    /// magic string to indicate extension aware request
90    pub magic: [u8; 16],
91    /// flags to indicate how to extend the attestation report
92    pub flags: u32,
93}
94
95impl Default for ReportReqExt {
96    fn default() -> Self {
97        Self {
98            data: [0u8; 64],
99            mnonce: [0u8; 16],
100            hash: [0u8; 32],
101            magic: ATTESTATION_EXT_MAGIC,
102            flags: 0,
103        }
104    }
105}
106
107impl ReportReqExt {
108    pub fn new(data: Option<[u8; 64]>, mnonce: [u8; 16], flags: u32) -> Result<Self, Error> {
109        let mut request = Self::default();
110
111        if let Some(data) = data {
112            request.data = data;
113        }
114
115        request.mnonce = mnonce;
116
117        request.calculate_hash()?;
118
119        request.flags = flags;
120
121        Ok(request)
122    }
123
124    fn calculate_hash(&mut self) -> Result<(), Error> {
125        let mut hasher = Hasher::new(MessageDigest::sm3())?;
126        hasher.update(self.data.as_ref())?;
127        hasher.update(self.mnonce.as_ref())?;
128        let hash = &hasher.finish()?;
129        self.hash.copy_from_slice(hash.as_ref());
130
131        Ok(())
132    }
133}
134
135/// Wrapper struct for both legacy attestation report and extended attestation
136/// report.
137#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub struct AttestationReportWrapper {
139    /// The magic string to indicate the attestation report type.
140    magic: [u8; 16],
141    /// The flags indicate how to parse the extended attestation report.
142    /// Note: the bit0 of flags must be 1.
143    flags: u32,
144    #[serde(with = "BigArray")]
145    /// Both the legacy and extended attestation report are padded to 4096 bytes.
146    data: [u8; 4096],
147}
148
149impl AttestationReportWrapper {
150    pub fn new(magic: [u8; 16], flags: u32, report: &mut [u8]) -> Self {
151        let mut bytes = [0u8; 4096];
152
153        let copy_len = std::cmp::min(report.len(), 4096);
154        bytes[..copy_len].copy_from_slice(&report[..copy_len]);
155
156        Self {
157            magic,
158            flags,
159            data: bytes,
160        }
161    }
162}
163
164/// Enum Containing the different versions of the Attestation Report
165///
166/// Since the release of the firmware API version 1.4, the attestation report
167/// support extended format. In order to keep backwards compatibility, use
168/// enum V1(AttestationReportV1) to handling legacy attestation report.
169///
170/// The V2(AttestationReportV2) is referred to as extended attestation report.
171#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
172pub enum AttestationReport {
173    /// Version 1 of the Attestation Report returned by the firmware
174    V1(AttestationReportV1),
175    /// Version 2 of the Attestation Report returned by the firmware
176    V2(AttestationReportV2),
177}
178
179impl TryFrom<&AttestationReportWrapper> for AttestationReport {
180    type Error = std::io::Error;
181
182    fn try_from(report_wrapper: &AttestationReportWrapper) -> Result<Self, Self::Error> {
183        match (report_wrapper.magic, report_wrapper.flags) {
184            (magic, _) if magic == *b"\0".repeat(16) => {
185                let report_v1: AttestationReportV1 = TryFrom::try_from(&report_wrapper.data[..])?;
186                Ok(AttestationReport::V1(report_v1))
187            }
188            (ATTESTATION_EXT_MAGIC, 0) => {
189                let report_v1: AttestationReportV1 = TryFrom::try_from(&report_wrapper.data[..])?;
190                Ok(AttestationReport::V1(report_v1))
191            }
192            (ATTESTATION_EXT_MAGIC, 1) => {
193                let report_v2: AttestationReportV2 = TryFrom::try_from(&report_wrapper.data[..])?;
194                Ok(AttestationReport::V2(report_v2))
195            }
196            _ => Err(std::io::Error::new(
197                std::io::ErrorKind::Other,
198                "Invalid AttestationReport".to_string(),
199            )),
200        }
201    }
202}
203
204impl AttestationReport {
205    /// Get version of the Attestation Report
206    pub fn version(&self) -> u32 {
207        match self {
208            Self::V1(_) => 1,
209            Self::V2(_) => 2,
210        }
211    }
212
213    /// Get tee info of the Attestation Report
214    pub fn tee_info(&self) -> TeeInfo<'_> {
215        match self {
216            Self::V1(report) => TeeInfo::V1(&report.tee_info),
217            Self::V2(report) => TeeInfo::V2(&report.tee_info),
218        }
219    }
220
221    /// Get the tee info signer of the attestation report
222    pub fn signer(&self) -> &TeeInfoSigner {
223        match self {
224            Self::V1(report) => &report.signer,
225            Self::V2(report) => &report.signer,
226        }
227    }
228}
229
230/// The response from the PSP containing the generated attestation report.
231///
232/// The Report is padded to exactly 4096 Bytes to make sure the page size
233/// matches.
234#[repr(C)]
235#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
236pub struct AttestationReportV1 {
237    /// The tee info generated by the firmware.
238    pub tee_info: TeeInfoV1,
239    /// The tee's evidence to verify the tee info's signature.
240    pub signer: TeeInfoSigner,
241    #[serde(with = "BigArray")]
242    /// Padding bits to meet the memory page alignment.
243    reserved:
244        [u8; 4096 - (std::mem::size_of::<TeeInfoV1>() + std::mem::size_of::<TeeInfoSigner>())],
245}
246
247// Compile-time check that the size is what is expected.
248const_assert!(std::mem::size_of::<AttestationReportV1>() == 4096);
249
250impl Default for AttestationReportV1 {
251    fn default() -> Self {
252        Self {
253            tee_info: Default::default(),
254            signer: Default::default(),
255            reserved: [0u8; 4096
256                - (std::mem::size_of::<TeeInfoV1>() + std::mem::size_of::<TeeInfoSigner>())],
257        }
258    }
259}
260
261impl TryFrom<&[u8]> for AttestationReportV1 {
262    type Error = std::io::Error;
263
264    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
265        bincode::deserialize(bytes).map_err(|e| {
266            std::io::Error::new(
267                std::io::ErrorKind::InvalidData,
268                format!("Failed to deserialize AttestationReportV1: {}", e),
269            )
270        })
271    }
272}
273
274/// The response from the PSP containing the generated extended attestation
275/// report.
276///
277/// The Report is padded to exactly 4096 Bytes to make sure the page size
278/// matches.
279#[repr(C)]
280#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
281pub struct AttestationReportV2 {
282    /// The tee info generated by the firmware.
283    pub tee_info: TeeInfoV2,
284    /// The tee's evidence to verify the tee info's signature.
285    pub signer: TeeInfoSigner,
286    /// Padding bits to meet the memory page alignment.
287    #[serde(with = "BigArray")]
288    reserved:
289        [u8; 4096 - (std::mem::size_of::<TeeInfoV2>() + std::mem::size_of::<TeeInfoSigner>())],
290}
291
292// Compile-time check that the size is what is expected.
293const_assert!(std::mem::size_of::<AttestationReportV2>() == 4096);
294
295impl Default for AttestationReportV2 {
296    fn default() -> Self {
297        Self {
298            tee_info: Default::default(),
299            signer: Default::default(),
300            reserved: [0u8; 4096
301                - (std::mem::size_of::<TeeInfoV2>() + std::mem::size_of::<TeeInfoSigner>())],
302        }
303    }
304}
305
306impl TryFrom<&[u8]> for AttestationReportV2 {
307    type Error = std::io::Error;
308
309    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
310        bincode::deserialize(bytes).map_err(|e| {
311            std::io::Error::new(
312                std::io::ErrorKind::InvalidData,
313                format!("Failed to deserialize AttestationReportV2: {}", e),
314            )
315        })
316    }
317}
318
319/// Enum Containing the different versions of the Tee Info struct
320///
321/// Since the release of the firmware API version 1.4, the tee info of the
322/// attestation report support extended format. In order to keep backwards
323/// compatibility, use enum V1(TeeInfoV1) to handling legacy tee info of the
324/// attestation report.
325///
326/// The V2(TeeInfoV2) is tee info struct for extended attestation report.
327pub enum TeeInfo<'a> {
328    /// Version 1 of Tee info
329    V1(&'a TeeInfoV1),
330    /// Version 2 of Tee info
331    V2(&'a TeeInfoV2),
332}
333
334impl TeeInfo<'_> {
335    /// Restore raw field from the Tee info
336    pub fn raw(&self, data: &[u8]) -> Vec<u8> {
337        let mut data_bytes = data.to_vec();
338
339        let anonce_bytes = self.anonce().to_le_bytes();
340
341        for (index, item) in data_bytes.iter_mut().enumerate() {
342            *item ^= anonce_bytes[index % 4];
343        }
344
345        data_bytes
346    }
347
348    /// Get user_pubkey_digest field
349    pub fn user_pubkey_digest(&self) -> Vec<u8> {
350        match *self {
351            Self::V1(tee_info) => self.raw(&tee_info.user_pubkey_digest[..]),
352            Self::V2(tee_info) => tee_info.user_pubkey_digest.to_vec(),
353        }
354    }
355
356    /// Get vm_id field
357    pub fn vm_id(&self) -> Vec<u8> {
358        match *self {
359            Self::V1(tee_info) => self.raw(&tee_info.vm_id[..]),
360            Self::V2(tee_info) => tee_info.vm_id.to_vec(),
361        }
362    }
363
364    /// Get vm_version field
365    pub fn vm_version(&self) -> Vec<u8> {
366        match *self {
367            Self::V1(tee_info) => self.raw(&tee_info.vm_version[..]),
368            Self::V2(tee_info) => tee_info.vm_version.to_vec(),
369        }
370    }
371
372    /// Get report_data field
373    pub fn report_data(&self) -> Vec<u8> {
374        match *self {
375            Self::V1(tee_info) => self.raw(&tee_info.report_data[..]),
376            Self::V2(tee_info) => tee_info.report_data.to_vec(),
377        }
378    }
379
380    /// Get mnonce field
381    pub fn mnonce(&self) -> Vec<u8> {
382        match *self {
383            Self::V1(tee_info) => self.raw(&tee_info.mnonce[..]),
384            Self::V2(tee_info) => tee_info.mnonce.to_vec(),
385        }
386    }
387
388    /// Get measure field
389    pub fn measure(&self) -> Vec<u8> {
390        match *self {
391            Self::V1(tee_info) => self.raw(&tee_info.measure[..]),
392            Self::V2(tee_info) => tee_info.measure.to_vec(),
393        }
394    }
395
396    /// Get policy field
397    pub fn policy(&self) -> GuestPolicy {
398        match *self {
399            Self::V1(tee_info) => tee_info.policy.xor(&self.anonce()),
400            Self::V2(tee_info) => tee_info.policy,
401        }
402    }
403
404    /// Get sig_usage field
405    pub fn sig_usage(&self) -> u32 {
406        match *self {
407            Self::V1(tee_info) => tee_info.sig_usage ^ self.anonce(),
408            Self::V2(tee_info) => tee_info.sig_usage,
409        }
410    }
411
412    /// Get sig_algo field
413    pub fn sig_algo(&self) -> u32 {
414        match *self {
415            Self::V1(tee_info) => tee_info.sig_algo ^ self.anonce(),
416            Self::V2(tee_info) => tee_info.sig_algo,
417        }
418    }
419
420    /// Get anonce field
421    pub fn anonce(&self) -> u32 {
422        match *self {
423            Self::V1(tee_info) => tee_info.anonce,
424            Self::V2(_) => 0,
425        }
426    }
427
428    /// Get build field
429    pub fn build(&self) -> u32 {
430        match *self {
431            Self::V1(_) => 0,
432            Self::V2(tee_info) => tee_info.build,
433        }
434    }
435
436    /// Get rtmr_version field
437    pub fn rtmr_version(&self) -> u16 {
438        match *self {
439            Self::V1(_) => 0,
440            Self::V2(tee_info) => tee_info.rtmr_version,
441        }
442    }
443
444    /// Get rtmr0 field
445    pub fn rtmr0(&self) -> &[u8] {
446        match *self {
447            Self::V1(_) => &[0u8; CSV_RTMR_REG_SIZE],
448            Self::V2(tee_info) => &tee_info.rtmr0,
449        }
450    }
451
452    /// Get rtmr1 field
453    pub fn rtmr1(&self) -> &[u8] {
454        match *self {
455            Self::V1(_) => &[0u8; CSV_RTMR_REG_SIZE],
456            Self::V2(tee_info) => &tee_info.rtmr1,
457        }
458    }
459
460    /// Get rtmr2 field
461    pub fn rtmr2(&self) -> &[u8] {
462        match *self {
463            Self::V1(_) => &[0u8; CSV_RTMR_REG_SIZE],
464            Self::V2(tee_info) => &tee_info.rtmr2,
465        }
466    }
467
468    /// Get rtmr3 field
469    pub fn rtmr3(&self) -> &[u8] {
470        match *self {
471            Self::V1(_) => &[0u8; CSV_RTMR_REG_SIZE],
472            Self::V2(tee_info) => &tee_info.rtmr3,
473        }
474    }
475
476    /// Get rtmr4 field
477    pub fn rtmr4(&self) -> &[u8] {
478        match *self {
479            Self::V1(_) => &[0u8; CSV_RTMR_REG_SIZE],
480            Self::V2(tee_info) => &tee_info.rtmr4,
481        }
482    }
483}
484
485impl<'a> TryFrom<&'a TeeInfo<'a>> for Signature {
486    type Error = std::io::Error;
487
488    #[inline]
489    fn try_from(value: &'a TeeInfo<'a>) -> Result<Self, std::io::Error> {
490        match *value {
491            TeeInfo::V1(v1) => {
492                let sig = Vec::try_from(&v1.sig)?;
493                Ok(Self {
494                    sig,
495                    id: None,
496                    usage: Usage::PEK,
497                    algo: None,
498                })
499            }
500            TeeInfo::V2(v2) => {
501                let sig = Vec::try_from(&v2.sig)?;
502                Ok(Self {
503                    sig,
504                    id: None,
505                    usage: Usage::PEK,
506                    algo: None,
507                })
508            }
509        }
510    }
511}
512
513impl<'a> Verifiable for (&'a Certificate, &'a TeeInfo<'a>) {
514    type Output = ();
515
516    fn verify(self) -> Result<(), std::io::Error> {
517        let (cert, tee_info) = self;
518        let key: PublicKey = cert.try_into()?;
519        let sig: Signature = tee_info.try_into()?;
520
521        match *tee_info {
522            TeeInfo::V1(v1) => key.verify(
523                v1,
524                &self.0.body.data.user_id[..self.0.body.data.uid_size as usize],
525                &sig,
526            ),
527            TeeInfo::V2(v2) => key.verify(
528                v2,
529                &self.0.body.data.user_id[..self.0.body.data.uid_size as usize],
530                &sig,
531            ),
532        }
533    }
534}
535
536/// Data provieded by the guest owner for requesting an attestation report
537/// from the HYGON Secure Processor.
538#[repr(C)]
539#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
540pub struct TeeInfoV1 {
541    /// Pubkey digest of the session used to secure communication between
542    /// user/hypervisor and PSP.
543    pub user_pubkey_digest: [u8; 32],
544    /// The identifier of the VM custommized by the guest owner.
545    pub vm_id: [u8; 16],
546    /// The version info of the VM customized by the guest owner.
547    pub vm_version: [u8; 16],
548    #[serde(with = "BigArray")]
549    /// The challenge data for the attestation.
550    pub report_data: [u8; 64],
551    /// The random nonce generated by user to protect struct TeeInfoSigner.
552    pub mnonce: [u8; 16],
553    /// The launch digest of the VM.
554    pub measure: [u8; 32],
555    /// The running policy of the VM.
556    pub policy: GuestPolicy,
557    /// The usage of the signature.
558    pub sig_usage: u32,
559    /// The algorithm of the signature.
560    pub sig_algo: u32,
561    /// The random nonce generated by firmware to tweak the attestation report.
562    pub anonce: u32,
563    /// The signature for the fields:
564    ///   user_pubkey_digest,
565    ///   vm_id,
566    ///   vm_version,
567    ///   report_data,
568    ///   mnonce,
569    ///   measure,
570    ///   policy,
571    pub sig: ecdsa::Signature,
572}
573
574// Compile-time check that the size is what is expected.
575const_assert!(std::mem::size_of::<TeeInfoV1>() == 0x150);
576
577impl Default for TeeInfoV1 {
578    fn default() -> Self {
579        Self {
580            user_pubkey_digest: Default::default(),
581            vm_id: Default::default(),
582            vm_version: Default::default(),
583            report_data: [0u8; 64],
584            mnonce: Default::default(),
585            measure: Default::default(),
586            policy: Default::default(),
587            sig_usage: Default::default(),
588            sig_algo: Default::default(),
589            anonce: Default::default(),
590            sig: Default::default(),
591        }
592    }
593}
594
595impl codicon::Encoder<crate::Body> for TeeInfoV1 {
596    type Error = std::io::Error;
597
598    fn encode(&self, mut writer: impl Write, _: crate::Body) -> Result<(), std::io::Error> {
599        writer.save(&self.user_pubkey_digest)?;
600        writer.save(&self.vm_id)?;
601        writer.save(&self.vm_version)?;
602        writer.save(&self.report_data)?;
603        writer.save(&self.mnonce)?;
604        writer.save(&self.measure)?;
605        writer.save(&self.policy)?;
606        Ok(())
607    }
608}
609
610/// Data provieded by the guest owner for requesting an extended attestation
611/// report from the HYGON Secure Processor.
612#[repr(C)]
613#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
614pub struct TeeInfoV2 {
615    /// Pubkey digest of the session used to secure communication between
616    /// user/hypervisor and PSP.
617    pub user_pubkey_digest: [u8; 32],
618    /// The identifier of the VM custommized by the guest owner.
619    pub vm_id: [u8; 16],
620    /// The version info of the VM customized by the guest owner.
621    pub vm_version: [u8; 16],
622    #[serde(with = "BigArray")]
623    /// The challenge data for the attestation.
624    pub report_data: [u8; 64],
625    /// The random nonce generated by user to protect struct TeeInfoSigner.
626    pub mnonce: [u8; 16],
627    /// The launch digest of the VM.
628    pub measure: [u8; 32],
629    /// The running policy of the VM.
630    pub policy: GuestPolicy,
631    /// The usage of the signature.
632    pub sig_usage: u32,
633    /// The algorithm of the signature.
634    pub sig_algo: u32,
635    /// The version of the firmware's build.
636    pub build: u32,
637    /// The version of the VM's rtmr.
638    pub rtmr_version: u16,
639    /// A reserved field, for future use.
640    pub reserved0: [u8; 14],
641    /// The rtmr register 0, it's always equals to @measure field.
642    pub rtmr0: [u8; CSV_RTMR_REG_SIZE],
643    /// The rtmr register 1.
644    pub rtmr1: [u8; CSV_RTMR_REG_SIZE],
645    /// The rtmr register 2.
646    pub rtmr2: [u8; CSV_RTMR_REG_SIZE],
647    /// The rtmr register 3.
648    pub rtmr3: [u8; CSV_RTMR_REG_SIZE],
649    /// The rtmr register 4.
650    pub rtmr4: [u8; CSV_RTMR_REG_SIZE],
651    #[serde(with = "BigArray")]
652    /// A reserved field, for future use.
653    pub reserved1: [u8; 656],
654    /// The signature for the fields:
655    ///   user_pubkey_digest,
656    ///   vm_id,
657    ///   vm_version,
658    ///   report_data,
659    ///   mnonce,
660    ///   measure,
661    ///   policy,
662    ///   sig_usage,
663    ///   sig_algo,
664    ///   build,
665    ///   rtmr_version,
666    ///   reserved0,
667    ///   rtmr0,
668    ///   rtmr1,
669    ///   rtmr2,
670    ///   rtmr3,
671    ///   rtmr4,
672    ///   reserved1,
673    pub sig: ecdsa::Signature,
674}
675
676// Compile-time check that the size is what is expected.
677const_assert!(std::mem::size_of::<TeeInfoV2>() == 0x490);
678
679impl Default for TeeInfoV2 {
680    fn default() -> Self {
681        Self {
682            user_pubkey_digest: Default::default(),
683            vm_id: Default::default(),
684            vm_version: Default::default(),
685            report_data: [0u8; 64],
686            mnonce: Default::default(),
687            measure: Default::default(),
688            policy: Default::default(),
689            sig_usage: Default::default(),
690            sig_algo: Default::default(),
691            build: Default::default(),
692            rtmr_version: Default::default(),
693            reserved0: Default::default(),
694            rtmr0: [0u8; CSV_RTMR_REG_SIZE],
695            rtmr1: [0u8; CSV_RTMR_REG_SIZE],
696            rtmr2: [0u8; CSV_RTMR_REG_SIZE],
697            rtmr3: [0u8; CSV_RTMR_REG_SIZE],
698            rtmr4: [0u8; CSV_RTMR_REG_SIZE],
699            reserved1: [0u8; 656],
700            sig: Default::default(),
701        }
702    }
703}
704
705impl codicon::Encoder<crate::Body> for TeeInfoV2 {
706    type Error = std::io::Error;
707
708    fn encode(&self, mut writer: impl Write, _: crate::Body) -> Result<(), std::io::Error> {
709        writer.save(&self.user_pubkey_digest)?;
710        writer.save(&self.vm_id)?;
711        writer.save(&self.vm_version)?;
712        writer.save(&self.report_data)?;
713        writer.save(&self.mnonce)?;
714        writer.save(&self.measure)?;
715        writer.save(&self.policy)?;
716        writer.save(&self.sig_usage)?;
717        writer.save(&self.sig_algo)?;
718        writer.save(&self.build)?;
719        writer.save(&self.rtmr_version)?;
720        writer.save(&self.reserved0)?;
721        writer.save(&self.rtmr0)?;
722        writer.save(&self.rtmr1)?;
723        writer.save(&self.rtmr2)?;
724        writer.save(&self.rtmr3)?;
725        writer.save(&self.rtmr4)?;
726        writer.save(&self.reserved1)?;
727        Ok(())
728    }
729}
730
731bitfield! {
732    /// The firmware associates each guest with a guest policy that the guest owner provides. The
733    /// firmware restricts what actions the hypervisor can take on the guest according to the guest policy.
734    /// The policy also indicates the minimum firmware version to for the guest.
735    ///
736    /// The guest owner provides the guest policy to the firmware during launch. The firmware then binds
737    /// the policy to the guest. The policy cannot be changed throughout the lifetime of the guest. The
738    /// policy is also migrated with the guest and enforced by the destination platform firmware.
739    ///
740    /// | Bit(s) | Name           | Description                                                                                 >
741    /// |--------|----------------|--------------------------------------------------------------------------------------------->
742    /// | 0      | NODBG          | Debugging of the guest is disallowed when set                                               >
743    /// | 1      | NOKS           | Sharing keys with other guests is disallowed when set                                       >
744    /// | 2      | ES             | CSV2 is required when set                                                                   >
745    /// | 3      | NOSEND         | Sending the guest to another platform is disallowed when set                                >
746    /// | 4      | DOMAIN         | The guest must not be transmitted to another platform that is not in the domain when set.   >
747    /// | 5      | CSV            | The guest must not be transmitted to another platform that is not CSV capable when set.     >
748    /// | 6      | CSV3           | The guest must not be transmitted to another platform that is not CSV3 capable when set.    >
749    /// | 7      | ASID_REUSE     | Sharing asids with other guests owned by same user is allowed when set                      >
750    /// | 11:8   | HSK_VERSION    | The guest must not be transmitted to another platform with a lower HSK version.             >
751    /// | 15:12  | CEK_VERSION    | The guest must not be transmitted to another platform with a lower CEK version.             >
752    /// | 23:16  | API_MAJOR      | The guest must not be transmitted to another platform with a lower platform version.        >
753    /// | 31:24  | API_MINOR      | The guest must not be transmitted to another platform with a lower platform version.        >
754    #[repr(C)]
755    #[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
756    pub struct GuestPolicy(u32);
757    impl Debug;
758    pub nodbg, _: 0, 0;
759    pub noks, _: 1, 1;
760    pub es, _: 2, 2;
761    pub nosend, _: 3, 3;
762    pub domain, _: 4, 4;
763    pub csv, _: 5, 5;
764    pub csv3, _: 6, 6;
765    pub asid_reuse, _: 7, 7;
766    pub hsk_version, _: 11, 8;
767    pub cek_version, _: 15, 12;
768    pub api_major, _: 23, 16;
769    pub api_minor, _: 31, 24;
770}
771
772impl GuestPolicy {
773    #[allow(dead_code)]
774    pub fn xor(&self, anonce: &u32) -> Self {
775        Self(self.0 ^ anonce)
776    }
777}
778
779#[repr(C)]
780#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
781pub struct TeeInfoSigner {
782    #[serde(with = "BigArray")]
783    pub pek_cert: [u8; 2084],
784    #[serde(with = "BigArray")]
785    pub sn: [u8; 64],
786    pub reserved: [u8; 32],
787    pub mac: [u8; 32],
788}
789
790fn xor_with_anonce(data: &mut [u8], anonce: &u32) -> Result<(), Error> {
791    let mut anonce_array = [0u8; 4];
792    anonce_array[..].copy_from_slice(&anonce.to_le_bytes());
793
794    for (index, item) in data.iter_mut().enumerate() {
795        *item ^= anonce_array[index % 4];
796    }
797
798    Ok(())
799}
800
801impl TeeInfoSigner {
802    /// Verifies the signature evidence's hmac.
803    pub fn verify(
804        &mut self,
805        input_mnonce: &[u8],
806        mnonce: &[u8],
807        anonce: &u32,
808    ) -> Result<(), Error> {
809        let mut real_mnonce = Vec::from(mnonce);
810        xor_with_anonce(&mut real_mnonce, anonce)?;
811
812        if real_mnonce != input_mnonce {
813            return Err(Error::BadSignature);
814        }
815
816        let key = pkey::PKey::hmac(&real_mnonce)?;
817        let mut sig = sign::Signer::new(MessageDigest::sm3(), &key)?;
818
819        sig.update(&self.pek_cert)?;
820        sig.update(&self.sn)?;
821        sig.update(&self.reserved)?;
822
823        if sig.sign_to_vec()? != self.mac {
824            return Err(Error::BadSignature);
825        }
826
827        // restore pek cert and serial number.
828        self.restore(anonce)?;
829
830        Ok(())
831    }
832
833    fn restore(&mut self, anonce: &u32) -> Result<(), Error> {
834        xor_with_anonce(&mut self.pek_cert, anonce)?;
835        xor_with_anonce(&mut self.sn, anonce)?;
836
837        // reset reserved to 0.
838        self.reserved.fill(0);
839
840        Ok(())
841    }
842}
843
844impl Default for TeeInfoSigner {
845    fn default() -> Self {
846        Self {
847            pek_cert: [0u8; 2084],
848            sn: [0u8; 64],
849            reserved: Default::default(),
850            mac: Default::default(),
851        }
852    }
853}
854
855#[cfg(test)]
856mod test {
857    mod report_req {
858        use crate::api::guest::types::ReportReq;
859        #[test]
860        pub fn test_new() {
861            let data: [u8; 64] = [
862                103, 198, 105, 115, 81, 255, 74, 236, 41, 205, 186, 171, 242, 251, 227, 70, 124,
863                194, 84, 248, 27, 232, 231, 141, 118, 90, 46, 99, 51, 159, 201, 154, 102, 50, 13,
864                183, 49, 88, 163, 90, 37, 93, 5, 23, 88, 233, 94, 212, 171, 178, 205, 198, 155,
865                180, 84, 17, 14, 130, 116, 65, 33, 61, 220, 135,
866            ];
867            let mnonce: [u8; 16] = [
868                112, 233, 62, 161, 65, 225, 252, 103, 62, 1, 126, 151, 234, 220, 107, 150,
869            ];
870            let hash: [u8; 32] = [
871                19, 76, 8, 98, 33, 246, 247, 155, 28, 21, 245, 185, 118, 74, 162, 128, 82, 15, 160,
872                233, 212, 130, 106, 177, 89, 6, 119, 243, 130, 21, 3, 153,
873            ];
874            let expected: ReportReq = ReportReq { data, mnonce, hash };
875
876            let actual: ReportReq = ReportReq::new(Some(data), mnonce).unwrap();
877
878            assert_eq!(expected, actual);
879        }
880
881        #[test]
882        #[should_panic]
883        pub fn test_new_error() {
884            let data: [u8; 64] = [
885                103, 198, 105, 115, 81, 255, 74, 236, 41, 205, 186, 171, 242, 251, 227, 70, 124,
886                194, 84, 248, 27, 232, 231, 141, 118, 90, 46, 99, 51, 159, 201, 154, 102, 50, 13,
887                183, 49, 88, 163, 90, 37, 93, 5, 23, 88, 233, 94, 212, 171, 178, 205, 198, 155,
888                180, 84, 17, 14, 130, 116, 65, 33, 61, 220, 135,
889            ];
890            let mnonce: [u8; 16] = [
891                112, 233, 62, 161, 65, 225, 252, 103, 62, 1, 126, 151, 234, 220, 107, 150,
892            ];
893            let wrong_mnonce: [u8; 16] = [
894                0, 233, 62, 161, 65, 225, 252, 103, 62, 1, 126, 151, 234, 220, 107, 150,
895            ];
896            let hash: [u8; 32] = [
897                19, 76, 8, 98, 33, 246, 247, 155, 28, 21, 245, 185, 118, 74, 162, 128, 82, 15, 160,
898                233, 212, 130, 106, 177, 89, 6, 119, 243, 130, 21, 3, 153,
899            ];
900            let expected: ReportReq = ReportReq { data, mnonce, hash };
901
902            let actual: ReportReq = ReportReq::new(Some(data), wrong_mnonce).unwrap();
903
904            assert_eq!(expected, actual);
905        }
906    }
907}