Skip to main content

sev/firmware/guest/types/
snp.rs

1// SPDX-License-Identifier: Apache-2.0
2
3#[cfg(any(feature = "openssl", feature = "crypto_nossl"))]
4use crate::certs::snp::{Certificate, Chain, Verifiable};
5
6use crate::{
7    certs::snp::ecdsa::Signature,
8    error::AttestationReportError,
9    firmware::host::TcbVersion,
10    parser::{ByteParser, Decoder, Encoder},
11    util::{
12        hexline::HexLine,
13        parser_helper::{ReadExt, WriteExt},
14    },
15    Generation,
16};
17
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20#[cfg(feature = "serde")]
21use serde_big_array::BigArray;
22
23use std::{
24    fmt::Display,
25    io::{Cursor, Read, Write},
26    ops::Range,
27};
28
29#[cfg(any(feature = "openssl", feature = "crypto_nossl"))]
30use std::convert::TryFrom;
31
32#[cfg(feature = "openssl")]
33use std::io::Error;
34
35use bitfield::bitfield;
36
37#[cfg(feature = "openssl")]
38use openssl::{ecdsa::EcdsaSig, sha::Sha384};
39
40const ATT_REP_FW_LEN: usize = 1184;
41const CHIP_ID_RANGE: Range<usize> = 0x1A0..0x1E0;
42const CPUID_FAMILY_ID_BYTES: usize = 0x188;
43const CPUID_MODEL_ID_BYTES: usize = 0x189;
44
45/// Structure of required data for fetching the derived key.
46#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
47pub struct DerivedKey {
48    /// Selects the root key to derive the key from.
49    /// 0: Indicates VCEK.
50    /// 1: Indicates VMRK.
51    root_key_select: u32,
52
53    /// Reserved, must be zero
54    _reserved_0: u32,
55
56    /// What data will be mixed into the derived key.
57    pub guest_field_select: GuestFieldSelect,
58
59    /// The VMPL to mix into the derived key. Must be greater than or equal
60    /// to the current VMPL.
61    pub vmpl: u32,
62
63    /// The guest SVN to mix into the key. Must not exceed the guest SVN
64    /// provided at launch in the ID block.
65    pub guest_svn: u32,
66
67    /// The TCB version to mix into the derived key. Must not
68    /// exceed CommittedTcb.
69    pub tcb_version: u64,
70
71    /// The mitigation vector value to mix into the derived key.
72    /// Specific bit settings corresponding to mitigations required for Guest operation.
73    pub launch_mit_vector: Option<u64>,
74}
75
76impl DerivedKey {
77    /// Create a new instance for requesting an DerivedKey.
78    pub fn new(
79        root_key_select: bool,
80        guest_field_select: GuestFieldSelect,
81        vmpl: u32,
82        guest_svn: u32,
83        tcb_version: u64,
84        launch_mit_vector: Option<u64>,
85    ) -> Self {
86        Self {
87            root_key_select: u32::from(root_key_select),
88            _reserved_0: Default::default(),
89            guest_field_select,
90            vmpl,
91            guest_svn,
92            tcb_version,
93            launch_mit_vector,
94        }
95    }
96
97    /// Obtain a copy of the root key select value (Private Field)
98    pub fn get_root_key_select(&self) -> u32 {
99        self.root_key_select
100    }
101}
102
103bitfield! {
104    /// Data which will be mixed into the derived key.
105    ///
106    /// | Bit(s) | Name | Description |
107    /// |--------|------|-------------|
108    /// |0|GUEST_POLICY|Indicates that the guest policy will be mixed into the key.|
109    /// |1|IMAGE_ID|Indicates that the image ID of the guest will be mixed into the key.|
110    /// |2|FAMILY_ID|Indicates the family ID of the guest will be mixed into the key.|
111    /// |3|MEASUREMENT|Indicates the measurement of the guest during launch will be mixed into the key.|
112    /// |4|GUEST_SVN|Indicates that the guest-provided SVN will be mixed into the key.|
113    /// |5|TCB_VERSION|Indicates that the guest-provided TCB_VERSION will be mixed into the key.|
114    /// |6|LAUNCH_MIT_VECTOR|Indicates that the guest-provided LAUNCH_MIT_VECTOR will be mixed into the key.|
115    /// |63:7|\-|Reserved. Must be zero.|
116    #[repr(C)]
117    #[derive(Default, Copy, Clone,PartialEq, Eq, PartialOrd, Ord)]
118    pub struct GuestFieldSelect(u64);
119    impl Debug;
120    /// Check/Set guest policy inclusion in derived key.
121    pub get_guest_policy, set_guest_policy: 0;
122    /// Check/Set image id inclusion in derived key.
123    pub get_image_id, set_image_id: 1;
124    /// Check/Set family id inclusion in derived key.
125    pub get_family_id, set_family_id: 2;
126    /// Check/Set measurement inclusion in derived key.
127    pub get_measurement, set_measurement: 3;
128    /// Check/Set svn inclusion in derived key.
129    pub get_svn, set_svn: 4;
130    /// Check/Set tcb version inclusion in derived key.
131    pub get_tcb_version, set_tcb_version: 5;
132     /// Indicates that the guest-provied LAUNCH_MIT_VECTOR will be mixed into the key.
133    pub get_launch_mit_vector, set_launch_mit_vector: 6;
134}
135
136#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
137#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
138/// A semver formatted version.
139pub struct Version {
140    /// Major Version
141    pub major: u8,
142    /// Minor Version
143    pub minor: u8,
144    /// Build Version
145    pub build: u8,
146}
147
148impl Version {
149    /// Create a new version.
150    pub fn new(major: u8, minor: u8, build: u8) -> Self {
151        Self {
152            major,
153            minor,
154            build,
155        }
156    }
157}
158
159impl std::fmt::Display for Version {
160    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161        write!(f, "{}.{}.{}", self.major, self.minor, self.build)
162    }
163}
164
165impl Encoder<()> for Version {
166    fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> {
167        writer.write_bytes(self.build, ())?;
168        writer.write_bytes(self.minor, ())?;
169        writer.write_bytes(self.major, ())?;
170        Ok(())
171    }
172}
173
174impl Decoder<()> for Version {
175    fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
176        let build = reader.read_bytes()?;
177        let minor = reader.read_bytes()?;
178        let major = reader.read_bytes()?;
179        Ok(Self {
180            major,
181            minor,
182            build,
183        })
184    }
185}
186
187impl ByteParser<()> for Version {
188    type Bytes = [u8; 3];
189    const EXPECTED_LEN: Option<usize> = Some(3);
190}
191
192/// Possible variants of the attestation report.
193pub enum ReportVariant {
194    /// Version 2 of the Attestation Report.
195    V2,
196
197    /// Version 3 of the Attestation Report for PreTurin CPUs.
198    V3,
199
200    /// Version 5 of the Attestation Report
201    V5,
202}
203
204impl Encoder<()> for ReportVariant {
205    fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> {
206        match self {
207            ReportVariant::V2 => writer.write_bytes(2u32, ())?,
208            ReportVariant::V3 => writer.write_bytes(3u32, ())?,
209            ReportVariant::V5 => writer.write_bytes(5u32, ())?,
210        };
211        Ok(())
212    }
213}
214
215impl Decoder<()> for ReportVariant {
216    fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
217        let version: u32 = reader.read_bytes()?;
218        Ok(match version {
219            0 | 1 => return Err(std::io::ErrorKind::Unsupported.into()),
220            2 => Self::V2,
221            3 | 4 => Self::V3,
222            5 => Self::V5,
223            _ => Self::V5,
224        })
225    }
226}
227
228impl ByteParser<()> for ReportVariant {
229    type Bytes = [u8; 4];
230    const EXPECTED_LEN: Option<usize> = Some(4);
231}
232
233/// Attestation Report for SEV-SNP guests.
234/// These are all the possible fields in the attestation report.
235/// Optional fields are set to none or a value depending on the version the system has.
236/// Added in version 3:
237/// The CPUID Family, Model and Stepping fields
238/// The Alias_Check_Complete field in the PlatformInfo field
239/// Added in version 5:
240/// The launch_mit_vector and current_mit_vector fields
241/// The page_swap_disabled field in the GuestPolicy field
242/// The SEV-TIO field in the PlatformInfo field
243///
244/// # Compatibility notice
245///
246/// This legacy eager-parsing model will be replaced in the next breaking
247/// release by a two-stage attestation report API that separates unverified
248/// report framing from verified report-body parsing.
249///
250/// Code that depends directly on `AttestationReport` should expect to migrate
251/// in the next breaking release.
252#[repr(C)]
253#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
254#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
255pub struct AttestationReport {
256    /// Version number of this attestation report. Set to 2h for this specification.
257    pub version: u32,
258    /// The guest SVN.
259    pub guest_svn: u32,
260    /// The guest policy.
261    pub policy: GuestPolicy,
262    /// The family ID provided at launch.
263    pub family_id: [u8; 16],
264    /// The image ID provided at launch.
265    pub image_id: [u8; 16],
266    /// The request VMPL for the attestation report.
267    pub vmpl: u32,
268    /// The signature algorithm used to sign this report.
269    pub sig_algo: u32,
270    /// Current TCB. See SNPTcbVersion
271    pub current_tcb: TcbVersion,
272    /// Information about the platform. See PlatformInfo
273    pub plat_info: PlatformInfo,
274    /// Information related to signing keys in the report. See KeyInfo
275    pub key_info: KeyInfo,
276
277    /// Guest-provided 512 Bits of Data
278    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
279    pub report_data: [u8; 64],
280
281    /// The measurement calculated at launch.
282    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
283    pub measurement: [u8; 48],
284
285    /// Data provided by the hypervisor at launch.
286    pub host_data: [u8; 32],
287
288    /// SHA-384 digest of the ID public key that signed the ID block provided
289    /// in SNP_LANUNCH_FINISH.
290    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
291    pub id_key_digest: [u8; 48],
292
293    /// SHA-384 digest of the Author public key that certified the ID key,
294    /// if provided in SNP_LAUNCH_FINSIH. Zeroes if AUTHOR_KEY_EN is 1.
295    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
296    pub author_key_digest: [u8; 48],
297    /// Report ID of this guest.
298    pub report_id: [u8; 32],
299    /// Report ID of this guest's migration agent (if applicable).
300    pub report_id_ma: [u8; 32],
301    /// Reported TCB version used to derive the VCEK that signed this report.
302    pub reported_tcb: TcbVersion,
303    /// CPUID Familiy ID (Combined Extended Family ID and Family ID)
304    pub cpuid_fam_id: Option<u8>,
305    /// CPUID Model (Combined Extended Model and Model fields)
306    pub cpuid_mod_id: Option<u8>,
307    /// CPUID Stepping
308    pub cpuid_step: Option<u8>,
309
310    /// If MaskChipId is set to 0, Identifier unique to the chip.
311    /// Otherwise set to 0h.
312    #[cfg_attr(feature = "serde", serde(with = "BigArray"))]
313    pub chip_id: [u8; 64],
314    /// CommittedTCB
315    pub committed_tcb: TcbVersion,
316    /// The build number of CurrentVersion
317    pub current: Version,
318    /// The build number of CommittedVersion
319    pub committed: Version,
320    /// The CurrentTcb at the time the guest was launched or imported.
321    pub launch_tcb: TcbVersion,
322    /// The verified mitigation vecor value at the time the guest was launched (LaunchMitVector).
323    pub launch_mit_vector: Option<u64>,
324    /// Value is set to the current verified mitigation vectore value (CurrentMitVector).
325    pub current_mit_vector: Option<u64>,
326    /// Signature of bytes 0 to 0x29F inclusive of this report.
327    /// The format of the signature is found within Signature.
328    pub signature: Signature,
329}
330
331impl Default for AttestationReport {
332    fn default() -> Self {
333        Self {
334            version: Default::default(),
335            guest_svn: Default::default(),
336            policy: Default::default(),
337            family_id: Default::default(),
338            image_id: Default::default(),
339            vmpl: Default::default(),
340            sig_algo: Default::default(),
341            current_tcb: Default::default(),
342            plat_info: Default::default(),
343            key_info: Default::default(),
344            report_data: [0u8; 64],
345            measurement: [0u8; 48],
346            host_data: Default::default(),
347            id_key_digest: [0u8; 48],
348            author_key_digest: [0u8; 48],
349            report_id: Default::default(),
350            report_id_ma: Default::default(),
351            reported_tcb: Default::default(),
352            cpuid_fam_id: Default::default(),
353            cpuid_mod_id: Default::default(),
354            cpuid_step: Default::default(),
355            chip_id: [0u8; 64],
356            committed_tcb: Default::default(),
357            current: Default::default(),
358            committed: Default::default(),
359            launch_tcb: Default::default(),
360            launch_mit_vector: Default::default(),
361            current_mit_vector: Default::default(),
362            signature: Default::default(),
363        }
364    }
365}
366
367impl Encoder<()> for AttestationReport {
368    fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> {
369        // Determine the variant based on version and CPUID step
370        let variant = match self.version {
371            2 => ReportVariant::V2,
372            3 | 4 => ReportVariant::V3,
373            _ => ReportVariant::V5,
374        };
375
376        let generation = match variant {
377            ReportVariant::V2 => {
378                if Self::chip_id_is_turin_like(&self.chip_id)? {
379                    Generation::Turin
380                } else {
381                    Generation::Genoa
382                }
383            }
384            _ => {
385                let family = self.cpuid_fam_id.unwrap_or(0);
386                let model = self.cpuid_mod_id.unwrap_or(0);
387                Generation::identify_cpu(family, model)?
388            }
389        };
390
391        // Write version (common to all variants)
392        writer.write_bytes(self.version, ())?;
393        writer.write_bytes(self.guest_svn, ())?;
394        writer.write_bytes(self.policy, ())?;
395        writer.write_bytes(self.family_id, ())?;
396        writer.write_bytes(self.image_id, ())?;
397        writer.write_bytes(self.vmpl, ())?;
398        writer.write_bytes(self.sig_algo, ())?;
399        writer.write_bytes(self.current_tcb, generation)?;
400        writer.write_bytes(self.plat_info, ())?;
401        writer.write_bytes(self.key_info, ())?;
402        writer
403            .skip_bytes::<4>()?
404            .write_bytes(self.report_data, ())?;
405        writer.write_bytes(self.measurement, ())?;
406        writer.write_bytes(self.host_data, ())?;
407        writer.write_bytes(self.id_key_digest, ())?;
408        writer.write_bytes(self.author_key_digest, ())?;
409        writer.write_bytes(self.report_id, ())?;
410        writer.write_bytes(self.report_id_ma, ())?;
411        writer.write_bytes(self.reported_tcb, generation)?;
412
413        // Write CPUID fields based on variant
414        match variant {
415            ReportVariant::V2 => {
416                // V2 doesn't have CPUID fields
417                writer.skip_bytes::<24>()?.write_bytes(self.chip_id, ())?;
418            }
419            _ => {
420                // Write CPUID fields for V3 and V4
421                writer.write_bytes(self.cpuid_fam_id.unwrap_or(0), ())?;
422                writer.write_bytes(self.cpuid_mod_id.unwrap_or(0), ())?;
423                writer.write_bytes(self.cpuid_step.unwrap_or(0), ())?;
424                writer.skip_bytes::<21>()?.write_bytes(self.chip_id, ())?;
425            }
426        }
427
428        // Write committed TCB based on variant
429        writer.write_bytes(self.committed_tcb, generation)?;
430        writer.write_bytes(self.current, ())?;
431        writer.skip_bytes::<1>()?.write_bytes(self.committed, ())?;
432        writer
433            .skip_bytes::<1>()?
434            .write_bytes(self.launch_tcb, generation)?;
435
436        // Write launch and current mitigation vectors based on variant
437        match variant {
438            ReportVariant::V2 | ReportVariant::V3 => {
439                writer
440                    .skip_bytes::<168>()?
441                    .write_bytes(self.signature, ())?;
442            }
443            _ => {
444                writer.write_bytes(self.launch_mit_vector.unwrap_or(0), ())?;
445                writer.write_bytes(self.current_mit_vector.unwrap_or(0), ())?;
446                writer
447                    .skip_bytes::<152>()?
448                    .write_bytes(self.signature, ())?;
449            }
450        }
451
452        Ok(())
453    }
454}
455
456impl Decoder<()> for AttestationReport {
457    fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
458        let mut bytes = vec![0u8; ATT_REP_FW_LEN];
459        reader.read_exact(&mut bytes)?;
460
461        let variant = ReportVariant::from_bytes(&bytes[0..4])?;
462
463        let generation = match variant {
464            ReportVariant::V2 => {
465                if Self::chip_id_is_turin_like(&bytes[CHIP_ID_RANGE])? {
466                    Generation::Turin
467                } else {
468                    Generation::Genoa
469                }
470            }
471            _ => {
472                let family = &bytes[CPUID_FAMILY_ID_BYTES];
473                let model = &bytes[CPUID_MODEL_ID_BYTES];
474                Generation::identify_cpu(*family, *model)?
475            }
476        };
477
478        let mut stepper = Cursor::new(&bytes[..]);
479
480        let version = stepper.read_bytes()?;
481        let guest_svn = stepper.read_bytes()?;
482        let policy = stepper.read_bytes()?;
483        let family_id = stepper.read_bytes()?;
484        let image_id = stepper.read_bytes()?;
485        let vmpl = stepper.read_bytes()?;
486        let sig_algo = stepper.read_bytes()?;
487
488        let current_tcb = stepper.read_bytes_with(generation)?;
489        let plat_info = stepper.read_bytes()?;
490        let key_info = stepper.read_bytes()?;
491        let report_data = stepper.skip_bytes::<4>()?.read_bytes()?;
492        let measurement = stepper.read_bytes()?;
493        let host_data = stepper.read_bytes()?;
494        let id_key_digest = stepper.read_bytes()?;
495        let author_key_digest = stepper.read_bytes()?;
496        let report_id = stepper.read_bytes()?;
497        let report_id_ma = stepper.read_bytes()?;
498        let reported_tcb = stepper.read_bytes_with(generation)?;
499
500        // CPUID fields were added in V3 and later.
501        let (cpuid_fam_id, cpuid_mod_id, cpuid_step, chip_id) = match variant {
502            ReportVariant::V2 => (None, None, None, stepper.skip_bytes::<24>()?.read_bytes()?),
503            _ => (
504                Some(stepper.read_bytes()?),
505                Some(stepper.read_bytes()?),
506                Some(stepper.read_bytes()?),
507                stepper.skip_bytes::<21>()?.read_bytes()?,
508            ),
509        };
510
511        let committed_tcb = stepper.read_bytes_with(generation)?;
512        let current = stepper.read_bytes()?;
513        let committed = stepper.skip_bytes::<1>()?.read_bytes()?;
514        let launch_tcb = stepper.skip_bytes::<1>()?.read_bytes_with(generation)?;
515
516        // mit vecor fields were added in V5 and later.
517        let (launch_mit_vector, current_mit_vector, signature) = match variant {
518            ReportVariant::V2 | ReportVariant::V3 => {
519                (None, None, stepper.skip_bytes::<168>()?.read_bytes()?)
520            }
521            _ => (
522                Some(stepper.read_bytes()?),
523                Some(stepper.read_bytes()?),
524                stepper.skip_bytes::<152>()?.read_bytes()?,
525            ),
526        };
527
528        Ok(Self {
529            version,
530            guest_svn,
531            policy,
532            family_id,
533            image_id,
534            vmpl,
535            sig_algo,
536            current_tcb,
537            plat_info,
538            key_info,
539            report_data,
540            measurement,
541            host_data,
542            id_key_digest,
543            author_key_digest,
544            report_id,
545            report_id_ma,
546            reported_tcb,
547            cpuid_fam_id,
548            cpuid_mod_id,
549            cpuid_step,
550            chip_id,
551            committed_tcb,
552            current,
553            committed,
554            launch_tcb,
555            launch_mit_vector,
556            current_mit_vector,
557            signature,
558        })
559    }
560}
561
562impl ByteParser<()> for AttestationReport {
563    type Bytes = [u8; ATT_REP_FW_LEN];
564    const EXPECTED_LEN: Option<usize> = Some(ATT_REP_FW_LEN);
565}
566
567impl AttestationReport {
568    #[inline(always)]
569    /// Checks if the MaskChipId is set to 1. If not, then it will check if
570    /// the CHIP_ID is Turin-like.
571    fn chip_id_is_turin_like(bytes: &[u8]) -> Result<bool, AttestationReportError> {
572        // Chip ID -> 0x1A0-0x1E0
573        if bytes == [0; 64] {
574            return Err(AttestationReportError::MaskedChipId);
575        }
576
577        // Last 8 bytes of CHIP_ID are zero, then it is Turin Like.
578        Ok(bytes[8..] == [0; 56])
579    }
580}
581
582impl Display for AttestationReport {
583    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
584        write!(
585            f,
586            r#"Attestation Report:
587
588Version:                      {}
589
590Guest SVN:                    {}
591
592{}
593
594Family ID:{}
595
596Image ID:{}
597
598VMPL:                         {}
599
600Signature Algorithm:          {}
601
602Current TCB:
603
604{}
605
606{}
607
608{}
609
610Report Data:{}
611
612Measurement:{}
613
614Host Data:{}
615
616ID Key Digest:{}
617
618Author Key Digest:{}
619
620Report ID:{}
621
622Report ID Migration Agent:{}
623
624Reported TCB:
625
626{}
627
628CPUID Family ID:              {}
629
630CPUID Model ID:               {}
631
632CPUID Stepping:               {}
633
634Chip ID:{}
635
636Committed TCB:
637
638{}
639
640Current Version:              {}
641
642Committed Version:            {}
643
644Launch TCB:
645
646{}
647
648Launch Mitigation Vector:     {}
649
650Current Mitigation Vector:    {}
651
652{}"#,
653            self.version,
654            self.guest_svn,
655            self.policy,
656            HexLine(&self.family_id),
657            HexLine(&self.image_id),
658            self.vmpl,
659            self.sig_algo,
660            self.current_tcb,
661            self.plat_info,
662            self.key_info,
663            HexLine(&self.report_data),
664            HexLine(&self.measurement),
665            HexLine(&self.host_data),
666            HexLine(&self.id_key_digest),
667            HexLine(&self.author_key_digest),
668            HexLine(&self.report_id),
669            HexLine(&self.report_id_ma),
670            self.reported_tcb,
671            self.cpuid_fam_id
672                .map_or("None".to_string(), |fam| fam.to_string()),
673            self.cpuid_mod_id
674                .map_or("None".to_string(), |model| model.to_string()),
675            self.cpuid_step
676                .map_or("None".to_string(), |step| step.to_string()),
677            HexLine(&self.chip_id),
678            self.committed_tcb,
679            self.current,
680            self.committed,
681            self.launch_tcb,
682            self.launch_mit_vector
683                .map_or("None".to_string(), |lmv| lmv.to_string()),
684            self.current_mit_vector
685                .map_or("None".to_string(), |cmv| cmv.to_string()),
686            self.signature
687        )
688    }
689}
690
691#[cfg(feature = "openssl")]
692impl Verifiable for (&Chain, &AttestationReport) {
693    type Output = ();
694
695    fn verify(self) -> std::io::Result<Self::Output> {
696        let vek = self.0.verify()?;
697
698        let sig = EcdsaSig::try_from(&self.1.signature)?;
699
700        let raw_report_bytes = self.1.to_bytes()?;
701
702        let measurable_bytes: &[u8] = &raw_report_bytes[..0x2a0];
703
704        let mut hasher = Sha384::new();
705        hasher.update(measurable_bytes);
706        let base_digest = hasher.finish();
707
708        let ec = vek.public_key()?.ec_key()?;
709        let signed = sig.verify(&base_digest, &ec)?;
710        match signed {
711            true => Ok(()),
712            false => Err(Error::other("VEK does not sign the attestation report")),
713        }
714    }
715}
716
717#[cfg(feature = "openssl")]
718impl Verifiable for (&Certificate, &AttestationReport) {
719    type Output = ();
720
721    fn verify(self) -> std::io::Result<Self::Output> {
722        let vek = self.0;
723
724        let sig = EcdsaSig::try_from(&self.1.signature)?;
725        let raw_report_bytes = self.1.to_bytes()?;
726
727        let measurable_bytes: &[u8] = &raw_report_bytes[..0x2a0];
728
729        let mut hasher = Sha384::new();
730        hasher.update(measurable_bytes);
731        let base_digest = hasher.finish();
732
733        let ec = vek.public_key()?.ec_key()?;
734        let signed = sig.verify(&base_digest, &ec)?;
735        match signed {
736            true => Ok(()),
737            false => Err(Error::other("VEK does not sign the attestation report")),
738        }
739    }
740}
741
742#[cfg(feature = "crypto_nossl")]
743impl Verifiable for (&Chain, &AttestationReport) {
744    type Output = ();
745
746    fn verify(self) -> std::io::Result<Self::Output> {
747        // According to Chapter 3 of the Versioned Chip Endorsement Key (VCEK) Certificate and the Versioned Loaded Endorsement Key (VLEK)
748        // Certificate specifications, both Versioned Endorsement Key certificates certify an ECDSA public key on curve P-384,
749        // with the signature hash algorithm being SHA-384.
750
751        let vek = self.0.verify()?;
752
753        let sig = p384::ecdsa::Signature::try_from(&self.1.signature)?;
754
755        let raw_report_bytes = self.1.to_bytes()?;
756
757        let measurable_bytes: &[u8] = &raw_report_bytes[..0x2a0];
758
759        use sha2::Digest;
760        let base_digest = sha2::Sha384::new_with_prefix(measurable_bytes);
761        let verifying_key = p384::ecdsa::VerifyingKey::from_sec1_bytes(vek.public_key_sec1())
762            .map_err(|e| {
763                std::io::Error::other(format!(
764                    "failed to deserialize public key from sec1 bytes: {e:?}"
765                ))
766            })?;
767        use p384::ecdsa::signature::DigestVerifier;
768        verifying_key.verify_digest(base_digest, &sig).map_err(|e| {
769            std::io::Error::other(format!("VEK does not sign the attestation report: {e:?}"))
770        })
771    }
772}
773
774#[cfg(feature = "crypto_nossl")]
775impl Verifiable for (&Certificate, &AttestationReport) {
776    type Output = ();
777
778    fn verify(self) -> std::io::Result<Self::Output> {
779        // According to Chapter 3 of the [Versioned Chip Endorsement Key (VCEK) Certificate and
780        // KDS Interface Specification][spec], the VCEK certificate certifies an ECDSA public key on curve P-384,
781        // and the signature hash algorithm is sha384.
782        // [spec]: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/57230.pdf
783
784        let vek = self.0;
785
786        let sig = p384::ecdsa::Signature::try_from(&self.1.signature)?;
787
788        let raw_report_bytes = self.1.to_bytes()?;
789
790        let measurable_bytes: &[u8] = &raw_report_bytes[..0x2a0];
791
792        use sha2::Digest;
793        let base_digest = sha2::Sha384::new_with_prefix(measurable_bytes);
794        let verifying_key = p384::ecdsa::VerifyingKey::from_sec1_bytes(vek.public_key_sec1())
795            .map_err(|e| {
796                std::io::Error::other(format!(
797                    "failed to deserialize public key from sec1 bytes: {e:?}"
798                ))
799            })?;
800        use p384::ecdsa::signature::DigestVerifier;
801        verifying_key.verify_digest(base_digest, &sig).map_err(|e| {
802            std::io::Error::other(format!("VEK does not sign the attestation report: {e:?}"))
803        })
804    }
805}
806
807bitfield! {
808    /// The firmware associates each guest with a guest policy that the guest owner provides. The
809    /// firmware restricts what actions the hypervisor can take on this guest according to the guest policy.
810    /// The policy also indicates the minimum firmware version to for the guest.
811    ///
812    /// The guest owner provides the guest policy to the firmware during launch. The firmware then binds
813    /// the policy to the guest. The policy cannot be changed throughout the lifetime of the guest. The
814    /// policy is also migrated with the guest and enforced by the destination platform firmware.
815    ///
816    /// | Bit(s) | Name              | Description                                                                                                        >
817    /// |--------|-------------------|-------------------------------------------------------------------------------------------------------------------->
818    /// | 7:0    | ABI_MINOR         | The minimum ABI minor version required for this guest to run.                                                      >
819    /// | 15:8   | ABI_MAJOR         | The minimum ABI major version required for this guest to run.                                                      >
820    /// | 16     | SMT               | 0: Host SMT usage is disallowed.<br>1: Host SMT usage is allowed.                                                  >
821    /// | 17     | -                 | Reserved. Must be one.                                                                                             >
822    /// | 18     | MIGRATE_MA        | 0: Association with a migration agent is disallowed.<br>1: Association with a migration agent is allowed           >
823    /// | 19     | DEBUG             | 0: Debugging is disallowed.<br>1: Debugging is allowed.                                                            >
824    /// | 20     | SINGLE_SOCKET     | 0: Guest can be activated on multiple sockets.<br>1: Guest can only be activated on one socket.                    >
825    /// | 21     | CXL_ALLOW         | 0: CXL cannot be populated with devices or memory.<br>1: CXL can be populated with devices or memory.              >
826    /// | 22     | MEM_AES_256_XTS   | 0: Allow either AES 128 XEX or AES 256 XTS for memory encryption.<br>1: Require AES 256 XTS for memory encryption. >
827    /// | 23     | RAPL_DIS          | 0: Allow Running Average Power Limit (RAPL).<br>1: RAPL must be disabled.                                          >
828    /// | 24     | CIPHERTEXT_HIDING | 0: Ciphertext hiding may be enabled or disabled.<br>1: Ciphertext hiding must be enabled.                          >
829    /// | 25     | PAGE_SWAP_DISABLE | 0: Disable Guest access to SNP_PAGE_MOVE, SNP_SWAP_OUT and SNP_SWAP_IN commands.                                   >
830    /// | 63:25  | -                 | Reserved. MBZ.                                                                                                     >
831    ///
832    #[repr(C)]
833    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
834    #[derive(Default, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
835    pub struct GuestPolicy(u64);
836    impl Debug;
837    /// ABI_MINOR field: Indicates the minor API version.
838    pub abi_minor, set_abi_minor: 7, 0;
839    /// ABI_MAJOR field: Indicates the minor API version.
840    pub abi_major, set_abi_major: 15, 8;
841    /// SMT_ALLOWED field: Indicates the if SMT should be permitted.
842    pub smt_allowed, set_smt_allowed: 16;
843    /// MIGRATE_MA_ALLOWED field: Indicates the if migration is permitted with
844    /// the migration agent.
845    pub migrate_ma_allowed, set_migrate_ma_allowed: 18;
846    /// DEBUG_ALLOWED field: Indicates the if debugging should is permitted.
847    pub debug_allowed, set_debug_allowed: 19;
848    /// SINGLE_SOCKET_REQUIRED field: Indicates the if a single socket is required.
849    pub single_socket_required, set_single_socket_required: 20;
850    /// CXL_ALLOW field: (1) can populate CXL devices/memory, (0) cannot populate CXL devices/memory
851    pub cxl_allowed, set_cxl_allowed: 21;
852    /// MEM_AES_256_XTS field: (1) require AES 256 XTS encryption, (0) allows either AES 128 XEX or AES 256 XTS encryption
853    pub mem_aes_256_xts, set_mem_aes_256_xts: 22;
854    /// RAPL_DIS field: (1) RAPL must be disabled, (0) allow RAPL
855    pub rapl_dis, set_rapl_dis: 23;
856    /// CIPHERTEXT_HIDING field: (1) ciphertext hiding must be enabled, (0) ciphertext hiding may be enabled/disabled
857    pub ciphertext_hiding, set_ciphertext_hiding: 24;
858    /// Guest policy to disable Guest access to SNP_PAGE_MOVE, SNP_SWAP_OUT, and SNP_SWAP_IN commands. If this policy
859    /// option is selected to disable these Page Move commands, then these commands will return POLICY_FAILURE.
860    /// 0: Do not disable Guest support for the commands.
861    /// 1: Disable Guest support for the commands.
862    pub page_swap_disabled, set_page_swap_disabled: 25;
863}
864
865impl Encoder<()> for GuestPolicy {
866    fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> {
867        writer.write_bytes(self.0, ())?;
868        Ok(())
869    }
870}
871
872impl Decoder<()> for GuestPolicy {
873    fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
874        let policy = reader.read_bytes()?;
875        Ok(Self(policy))
876    }
877}
878
879impl ByteParser<()> for GuestPolicy {
880    type Bytes = [u8; 8];
881    const EXPECTED_LEN: Option<usize> = Some(8);
882}
883
884impl Display for GuestPolicy {
885    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
886        write!(
887            f,
888            r#"Guest Policy (0x{:x}):
889  ABI Major:     {}
890  ABI Minor:     {}
891  SMT Allowed:   {}
892  Migrate MA:    {}
893  Debug Allowed: {}
894  Single Socket: {}
895  CXL Allowed:   {}
896  AEX 256 XTS:   {}
897  RAPL Allowed:  {}
898  Ciphertext hiding: {}
899  Page Swap Disable: {}"#,
900            self.0,
901            self.abi_major(),
902            self.abi_minor(),
903            self.smt_allowed(),
904            self.migrate_ma_allowed(),
905            self.debug_allowed(),
906            self.single_socket_required(),
907            self.cxl_allowed(),
908            self.mem_aes_256_xts(),
909            self.rapl_dis(),
910            self.ciphertext_hiding(),
911            self.page_swap_disabled()
912        )
913    }
914}
915
916impl From<GuestPolicy> for u64 {
917    fn from(value: GuestPolicy) -> Self {
918        // Bit 17 of the guest policy is reserved and must always be set to 1.
919        let reserved: u64 = 1 << 17;
920
921        value.0 | reserved
922    }
923}
924
925impl From<u64> for GuestPolicy {
926    fn from(value: u64) -> Self {
927        // Bit 17 of the guest policy is reserved and must always be set to 1.
928        let reserved: u64 = 1 << 17;
929
930        GuestPolicy(value | reserved)
931    }
932}
933
934bitfield! {
935    /// Version 2 PlatformInfo bitfield
936    /// A structure with a bit-field unsigned 64 bit integer:
937    /// Bit 0 representing the status of SMT enablement.
938    /// Bit 1 representing the status of TSME enablement.
939    /// Bit 2 indicates if ECC memory is used.
940    /// Bit 3 indicates if RAPL is disabled.
941    /// Bit 4 indicates if ciphertext hiding is enabled
942    /// Bit 5 indicates that alias detection has completed since the last system reset and there are no aliasing addresses. Resets to 0.
943    /// Bit 6 reserved
944    /// Bit 7 indicates that SEV-TIO is enabled.
945    /// Bits 8-63 are reserved.
946    #[repr(C)]
947    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
948    #[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
949    pub struct PlatformInfo(u64);
950    impl Debug;
951    /// Returns the bit state of SMT
952    pub smt_enabled, _: 0;
953    /// Returns the bit state of TSME.
954    pub tsme_enabled, _: 1;
955    /// Indicates that the platform is currently using ECC memory
956    pub ecc_enabled, _: 2;
957    /// Indicates that the RAPL feature is disabled
958    pub rapl_disabled, _: 3;
959    /// Indicates that ciphertext hiding is enabled
960    pub ciphertext_hiding_enabled, _: 4;
961    /// Indicates that alias detection has completed since the last system reset and there are no aliasing addresses. Resets to 0.
962    pub alias_check_complete, _: 5;
963    /// Indicates that SEV-TIO is enabled.
964    pub tio_enabled, _ : 7
965
966}
967
968impl Display for PlatformInfo {
969    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
970        write!(
971            f,
972            r#"Platform Info ({}):
973  SMT Enabled:               {}
974  TSME Enabled:              {}
975  ECC Enabled:               {}
976  RAPL Disabled:             {}
977  Ciphertext Hiding Enabled: {}
978  Alias Check Complete:      {}
979  SEV-TIO Enabled:           {}"#,
980            self.0,
981            self.smt_enabled(),
982            self.tsme_enabled(),
983            self.ecc_enabled(),
984            self.rapl_disabled(),
985            self.ciphertext_hiding_enabled(),
986            self.alias_check_complete(),
987            self.tio_enabled()
988        )
989    }
990}
991
992impl From<u64> for PlatformInfo {
993    fn from(value: u64) -> Self {
994        PlatformInfo(value)
995    }
996}
997
998impl From<PlatformInfo> for u64 {
999    fn from(value: PlatformInfo) -> Self {
1000        value.0
1001    }
1002}
1003
1004impl Encoder<()> for PlatformInfo {
1005    fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> {
1006        writer.write_bytes(self.0, ())?;
1007        Ok(())
1008    }
1009}
1010
1011impl Decoder<()> for PlatformInfo {
1012    fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
1013        let info = reader.read_bytes()?;
1014        Ok(Self(info))
1015    }
1016}
1017
1018impl ByteParser<()> for PlatformInfo {
1019    type Bytes = [u8; 8];
1020    const EXPECTED_LEN: Option<usize> = Some(8);
1021}
1022
1023bitfield! {
1024    /// When an attestation report is requested, the user can request to have the report to not be signed, or sign with different keys. The user may also
1025    /// pass in the author key when launching the guest. This field provides that information and will be present in the attestation report.
1026    ///
1027    /// | Bit(s) | Name              | Description                                                                                                        >
1028    /// |--------|-------------------|-------------------------------------------------------------------------------------------------------------------->
1029    /// | 0      | AUTHOR_KEY_EN     | Indicates that the digest of the author key is present in AUTHOR_KEY_DIGEST. Set to the value of GCTX.AuthorKeyEn. >
1030    /// | 1      | MASK_CHIP_KEY     | The value of MaskChipKey.                                                                                          >
1031    /// | 4:2    | SIGNING_KEY       | Encodes the key used to sign this report.                                                                          >
1032    /// | 5:31   | -                 | Reserved. Must be zero.                                                                                            >
1033    #[repr(C)]
1034    #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
1035    #[derive(Default, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
1036    pub struct KeyInfo(u32);
1037    impl Debug;
1038    /// AUTHOR_KEY_EN field: Indicates that the digest of the author key is present in AUTHOR_KEY_DIGEST
1039    pub author_key_en, _: 0;
1040    /// MASK_CHIP_KEY field: The value of MaskChipKey
1041    /// (0) Firmware signs the attestation report with either the VCEK OR VLEK.
1042    /// (1) The firmware writes 0s into the SIGNATURE field instead of signing the report.
1043    pub mask_chip_key, _: 1;
1044    /// SIGNING_KEY field: Encodes the key used to sign this report.
1045    /// (0) VCEK
1046    /// (1) VLEK
1047    /// (2-6) RESERVED
1048    /// (7) NONE
1049    pub signing_key, _: 4,2;
1050
1051}
1052
1053impl Encoder<()> for KeyInfo {
1054    fn encode(&self, writer: &mut impl Write, _: ()) -> Result<(), std::io::Error> {
1055        writer.write_bytes(self.0.to_le_bytes(), ())?;
1056        Ok(())
1057    }
1058}
1059
1060impl Decoder<()> for KeyInfo {
1061    fn decode(reader: &mut impl Read, _: ()) -> Result<Self, std::io::Error> {
1062        let info = reader.read_bytes()?;
1063        Ok(Self(info))
1064    }
1065}
1066
1067impl ByteParser<()> for KeyInfo {
1068    type Bytes = [u8; 4];
1069    const EXPECTED_LEN: Option<usize> = Some(4);
1070}
1071
1072impl From<u32> for KeyInfo {
1073    fn from(value: u32) -> Self {
1074        KeyInfo(value)
1075    }
1076}
1077
1078impl From<KeyInfo> for u32 {
1079    fn from(value: KeyInfo) -> Self {
1080        value.0
1081    }
1082}
1083
1084impl Display for KeyInfo {
1085    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1086        let signing_key = match self.signing_key() {
1087            0 => "vcek",
1088            1 => "vlek",
1089            7 => "none",
1090            _ => "unknown",
1091        };
1092
1093        write!(
1094            f,
1095            r#"Key Information:
1096    author key enabled: {}
1097    mask chip key:      {}
1098    signing key:        {}"#,
1099            self.author_key_en(),
1100            self.mask_chip_key(),
1101            signing_key
1102        )
1103    }
1104}
1105
1106#[cfg(test)]
1107mod tests {
1108
1109    use super::*;
1110    use std::{convert::TryInto, io::Write};
1111
1112    #[test]
1113    fn test_derive_key_new() {
1114        let expected: DerivedKey = DerivedKey {
1115            root_key_select: 0,
1116            _reserved_0: 0,
1117            guest_field_select: GuestFieldSelect(0),
1118            vmpl: 0,
1119            guest_svn: 0,
1120            tcb_version: 0,
1121            launch_mit_vector: None,
1122        };
1123
1124        let guest_field: GuestFieldSelect = GuestFieldSelect(0);
1125
1126        let actual: DerivedKey = DerivedKey::new(false, guest_field, 0, 0, 0, None);
1127
1128        assert_eq!(actual, expected);
1129    }
1130
1131    #[test]
1132    fn test_derive_key_get_root_key_select() {
1133        let dk_struct: DerivedKey = DerivedKey {
1134            root_key_select: 0,
1135            _reserved_0: 0,
1136            guest_field_select: GuestFieldSelect(0),
1137            vmpl: 0,
1138            guest_svn: 0,
1139            tcb_version: 0,
1140            launch_mit_vector: None,
1141        };
1142
1143        let expected: u32 = 0;
1144        let actual: u32 = dk_struct.get_root_key_select();
1145
1146        assert_eq!(actual, expected);
1147    }
1148
1149    #[test]
1150    fn test_guest_field_select_all_on() {
1151        let actual: GuestFieldSelect = GuestFieldSelect(0b111111);
1152
1153        assert!(actual.get_guest_policy());
1154        assert!(actual.get_image_id());
1155        assert!(actual.get_family_id());
1156        assert!(actual.get_measurement());
1157        assert!(actual.get_svn());
1158        assert!(actual.get_tcb_version());
1159    }
1160
1161    #[test]
1162    fn test_guest_field_select_all_off() {
1163        let actual: GuestFieldSelect = GuestFieldSelect(0);
1164
1165        assert!(!actual.get_guest_policy());
1166        assert!(!actual.get_image_id());
1167        assert!(!actual.get_family_id());
1168        assert!(!actual.get_measurement());
1169        assert!(!actual.get_svn());
1170        assert!(!actual.get_tcb_version());
1171    }
1172
1173    #[test]
1174    fn test_attestation_report_fmt() {
1175        let expected: &str = r#"Attestation Report:
1176
1177Version:                      0
1178
1179Guest SVN:                    0
1180
1181Guest Policy (0x0):
1182  ABI Major:     0
1183  ABI Minor:     0
1184  SMT Allowed:   false
1185  Migrate MA:    false
1186  Debug Allowed: false
1187  Single Socket: false
1188  CXL Allowed:   false
1189  AEX 256 XTS:   false
1190  RAPL Allowed:  false
1191  Ciphertext hiding: false
1192  Page Swap Disable: false
1193
1194Family ID:
119500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1196
1197Image ID:
119800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1199
1200VMPL:                         0
1201
1202Signature Algorithm:          0
1203
1204Current TCB:
1205
1206TCB Version:
1207  Microcode:   0
1208  SNP:         0
1209  TEE:         0
1210  Boot Loader: 0
1211  FMC:         None
1212
1213Platform Info (0):
1214  SMT Enabled:               false
1215  TSME Enabled:              false
1216  ECC Enabled:               false
1217  RAPL Disabled:             false
1218  Ciphertext Hiding Enabled: false
1219  Alias Check Complete:      false
1220  SEV-TIO Enabled:           false
1221
1222Key Information:
1223    author key enabled: false
1224    mask chip key:      false
1225    signing key:        vcek
1226
1227Report Data:
122800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
122900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
123000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
123100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1232
1233Measurement:
123400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
123500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
123600 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1237
1238Host Data:
123900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
124000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1241
1242ID Key Digest:
124300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
124400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
124500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1246
1247Author Key Digest:
124800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
124900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
125000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1251
1252Report ID:
125300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
125400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1255
1256Report ID Migration Agent:
125700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
125800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1259
1260Reported TCB:
1261
1262TCB Version:
1263  Microcode:   0
1264  SNP:         0
1265  TEE:         0
1266  Boot Loader: 0
1267  FMC:         None
1268
1269CPUID Family ID:              None
1270
1271CPUID Model ID:               None
1272
1273CPUID Stepping:               None
1274
1275Chip ID:
127600 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
127700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
127800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
127900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1280
1281Committed TCB:
1282
1283TCB Version:
1284  Microcode:   0
1285  SNP:         0
1286  TEE:         0
1287  Boot Loader: 0
1288  FMC:         None
1289
1290Current Version:              0.0.0
1291
1292Committed Version:            0.0.0
1293
1294Launch TCB:
1295
1296TCB Version:
1297  Microcode:   0
1298  SNP:         0
1299  TEE:         0
1300  Boot Loader: 0
1301  FMC:         None
1302
1303Launch Mitigation Vector:     None
1304
1305Current Mitigation Vector:    None
1306
1307Signature:
1308  R:
130900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131300 00 00 00 00 00 00 00
1314  S:
131500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131600 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
131900 00 00 00 00 00 00 00"#;
1320        assert_eq!(expected, AttestationReport::default().to_string())
1321    }
1322
1323    #[test]
1324    fn test_attestation_report_copy() {
1325        let expected: AttestationReport = AttestationReport::default();
1326
1327        let copy: AttestationReport = expected;
1328
1329        assert_eq!(expected, copy);
1330    }
1331
1332    #[test]
1333    fn test_guest_policy_zeroed() {
1334        let gp: GuestPolicy = GuestPolicy(0);
1335
1336        assert_eq!(gp.abi_minor(), 0);
1337        assert_eq!(gp.abi_major(), 0);
1338        assert!(!gp.smt_allowed());
1339        assert!(!gp.migrate_ma_allowed());
1340        assert!(!gp.debug_allowed());
1341        assert!(!gp.single_socket_required());
1342        assert!(!gp.cxl_allowed());
1343        assert!(!gp.mem_aes_256_xts());
1344        assert!(!gp.rapl_dis());
1345        assert!(!gp.ciphertext_hiding());
1346    }
1347
1348    #[test]
1349    fn test_guest_policy_max() {
1350        let gp: GuestPolicy = GuestPolicy(0b1111111111111111111111111);
1351
1352        assert_eq!(gp.abi_minor(), 0b11111111);
1353        assert_eq!(gp.abi_major(), 0b11111111);
1354        assert!(gp.smt_allowed());
1355        assert!(gp.migrate_ma_allowed());
1356        assert!(gp.debug_allowed());
1357        assert!(gp.single_socket_required());
1358        assert!(gp.cxl_allowed());
1359        assert!(gp.mem_aes_256_xts());
1360        assert!(gp.rapl_dis());
1361        assert!(gp.ciphertext_hiding());
1362    }
1363
1364    #[test]
1365    fn test_set_guest_policy_max() {
1366        let mut gp: GuestPolicy = Default::default();
1367
1368        assert_eq!(gp.abi_minor(), 0);
1369        gp.set_abi_minor(1);
1370        assert_eq!(gp.abi_minor(), 0b1);
1371
1372        assert_eq!(gp.abi_major(), 0);
1373        gp.set_abi_major(1);
1374        assert_eq!(gp.abi_major(), 0b1);
1375
1376        assert!(!gp.smt_allowed());
1377        gp.set_smt_allowed(true);
1378        assert!(gp.smt_allowed());
1379
1380        assert!(!gp.migrate_ma_allowed());
1381        gp.set_migrate_ma_allowed(true);
1382        assert!(gp.migrate_ma_allowed());
1383
1384        assert!(!gp.debug_allowed());
1385        gp.set_debug_allowed(true);
1386        assert!(gp.debug_allowed());
1387
1388        assert!(!gp.single_socket_required());
1389        gp.set_single_socket_required(true);
1390        assert!(gp.single_socket_required());
1391
1392        assert!(!gp.cxl_allowed());
1393        gp.set_cxl_allowed(true);
1394        assert!(gp.cxl_allowed());
1395
1396        assert!(!gp.mem_aes_256_xts());
1397        gp.set_mem_aes_256_xts(true);
1398        assert!(gp.mem_aes_256_xts());
1399
1400        assert!(!gp.rapl_dis());
1401        gp.set_rapl_dis(true);
1402        assert!(gp.rapl_dis());
1403
1404        assert!(!gp.ciphertext_hiding());
1405        gp.set_ciphertext_hiding(true);
1406        assert!(gp.ciphertext_hiding());
1407    }
1408
1409    #[test]
1410    fn test_guest_policy_from_u64() {
1411        let gp: GuestPolicy = GuestPolicy(5);
1412
1413        // Bit 17 of the guest policy is reserved and must always be set to 1.
1414        let expected: u64 = (1 << 17) | 5;
1415
1416        assert_eq!(u64::from(gp), expected);
1417    }
1418
1419    #[test]
1420    fn test_platform_info_zeroed() {
1421        let expected: PlatformInfo = PlatformInfo(0);
1422
1423        assert!(!expected.smt_enabled());
1424        assert!(!expected.tsme_enabled());
1425        assert!(!expected.ecc_enabled());
1426        assert!(!expected.rapl_disabled());
1427        assert!(!expected.ciphertext_hiding_enabled());
1428        assert!(!expected.alias_check_complete());
1429    }
1430
1431    #[test]
1432    fn test_platform_info_full() {
1433        let expected: PlatformInfo = PlatformInfo(0b111111);
1434
1435        assert!(expected.smt_enabled());
1436        assert!(expected.tsme_enabled());
1437        assert!(expected.ecc_enabled());
1438        assert!(expected.rapl_disabled());
1439        assert!(expected.ciphertext_hiding_enabled());
1440        assert!(expected.alias_check_complete());
1441    }
1442
1443    #[test]
1444    fn test_platform_info_fmt() {
1445        let expected: &str = r#"Platform Info (0):
1446  SMT Enabled:               false
1447  TSME Enabled:              false
1448  ECC Enabled:               false
1449  RAPL Disabled:             false
1450  Ciphertext Hiding Enabled: false
1451  Alias Check Complete:      false
1452  SEV-TIO Enabled:           false"#;
1453        let actual: PlatformInfo = PlatformInfo(0);
1454
1455        assert_eq!(expected, actual.to_string());
1456    }
1457
1458    #[test]
1459    fn test_key_info_zeroed() {
1460        let expected: KeyInfo = KeyInfo(0);
1461
1462        assert!(!expected.author_key_en());
1463        assert!(!expected.mask_chip_key());
1464
1465        assert_eq!(expected.signing_key(), 0);
1466    }
1467
1468    #[test]
1469    fn test_key_info_max() {
1470        let expected: KeyInfo = KeyInfo(0b11111);
1471
1472        assert!(expected.author_key_en());
1473        assert!(expected.mask_chip_key());
1474        assert_eq!(expected.signing_key(), 0b111);
1475    }
1476
1477    #[test]
1478    fn test_key_info_fmt_vcek() {
1479        let expected: &str = r#"Key Information:
1480    author key enabled: false
1481    mask chip key:      false
1482    signing key:        vcek"#;
1483        let actual: KeyInfo = KeyInfo(0);
1484
1485        assert_eq!(expected, actual.to_string());
1486    }
1487
1488    #[test]
1489    fn test_key_info_fmt_vlek() {
1490        let expected: &str = r#"Key Information:
1491    author key enabled: false
1492    mask chip key:      false
1493    signing key:        vlek"#;
1494        let actual: KeyInfo = KeyInfo(0b100);
1495
1496        assert_eq!(expected, actual.to_string());
1497    }
1498
1499    #[test]
1500    fn test_key_info_fmt_none() {
1501        let expected: &str = r#"Key Information:
1502    author key enabled: false
1503    mask chip key:      false
1504    signing key:        none"#;
1505        let actual: KeyInfo = KeyInfo(0b11100);
1506
1507        assert_eq!(expected, actual.to_string());
1508    }
1509
1510    #[test]
1511    fn test_key_info_fmt_unknown() {
1512        let expected: &str = r#"Key Information:
1513    author key enabled: false
1514    mask chip key:      false
1515    signing key:        unknown"#;
1516        let actual: KeyInfo = KeyInfo(0b11000);
1517
1518        assert_eq!(expected, actual.to_string());
1519    }
1520
1521    #[test]
1522    fn test_platform_info_v2_serialization() {
1523        let original = PlatformInfo(0b11111);
1524        // Test encoding and decoding
1525        let buffer = original.to_bytes().unwrap();
1526        let decoded = PlatformInfo::from_bytes(&buffer).unwrap();
1527
1528        assert_eq!(original, decoded);
1529    }
1530
1531    #[test]
1532    fn test_key_info_serialization() {
1533        let original = KeyInfo(0b11111);
1534
1535        // Test encoding and decoding
1536        let buffer = original.to_bytes().unwrap();
1537        let decoded = KeyInfo::from_bytes(&buffer).unwrap();
1538
1539        assert_eq!(original, decoded);
1540        assert!(decoded.author_key_en());
1541        assert!(decoded.mask_chip_key());
1542        assert_eq!(decoded.signing_key(), 0b111);
1543    }
1544
1545    #[test]
1546    fn test_guest_policy_serialization() {
1547        let mut original: GuestPolicy = Default::default();
1548        original.set_abi_major(2);
1549        original.set_abi_minor(1);
1550        original.set_smt_allowed(true);
1551        original.set_debug_allowed(true);
1552
1553        // Test bincode
1554        let buffer = original.to_bytes().unwrap();
1555        let decoded = GuestPolicy::from_bytes(&buffer).unwrap();
1556        assert_eq!(original, decoded);
1557    }
1558
1559    #[test]
1560    fn test_version_extraction() {
1561        let raw_v2 = [2, 0, 0, 0]; // Version 2
1562        let version = u32::from_le_bytes([raw_v2[0], raw_v2[1], raw_v2[2], raw_v2[3]]);
1563        assert_eq!(version, 2);
1564
1565        let raw_v3 = [3, 0, 0, 0]; // Version 3
1566        let version = u32::from_le_bytes([raw_v3[0], raw_v3[1], raw_v3[2], raw_v3[3]]);
1567        assert_eq!(version, 3);
1568    }
1569
1570    #[test]
1571    fn test_boundary_value_serialization() {
1572        // Test max values
1573        let platform_info = PlatformInfo(u64::MAX);
1574        let key_info = KeyInfo(u32::MAX);
1575        let guest_policy = GuestPolicy(u64::MAX);
1576
1577        // Verify serialization/deserialization preserves max values
1578        assert_eq!(
1579            platform_info,
1580            PlatformInfo::from_bytes(&platform_info.to_bytes().unwrap()).unwrap()
1581        );
1582        assert_eq!(
1583            key_info,
1584            KeyInfo::from_bytes(&key_info.to_bytes().unwrap()).unwrap()
1585        );
1586        assert_eq!(
1587            guest_policy,
1588            GuestPolicy::from_bytes(&guest_policy.to_bytes().unwrap()).unwrap()
1589        );
1590    }
1591
1592    #[test]
1593    fn test_guest_field_select_operations() {
1594        let mut field = GuestFieldSelect::default();
1595
1596        field.set_guest_policy(true);
1597        assert!(field.get_guest_policy());
1598
1599        field.set_image_id(true);
1600        assert!(field.get_image_id());
1601
1602        field.set_family_id(true);
1603        assert!(field.get_family_id());
1604
1605        field.set_measurement(true);
1606        assert!(field.get_measurement());
1607    }
1608
1609    #[test]
1610    fn test_derived_key_fields() {
1611        let key = DerivedKey::new(true, GuestFieldSelect(0xFF), 2, 3, 0x1234, None);
1612        assert_eq!(key.get_root_key_select(), 1);
1613        assert_eq!(key.vmpl, 2);
1614        assert_eq!(key.guest_svn, 3);
1615        assert_eq!(key.tcb_version, 0x1234);
1616    }
1617
1618    #[test]
1619    fn test_key_info_all_combinations() {
1620        let mut info = KeyInfo(0);
1621
1622        // Test VCEK
1623        assert_eq!(info.signing_key(), 0);
1624        assert!(!info.author_key_en());
1625
1626        // Test VLEK
1627        info = KeyInfo(0b100);
1628        assert_eq!(info.signing_key(), 1);
1629
1630        // Test None
1631        info = KeyInfo(0b11100);
1632        assert_eq!(info.signing_key(), 7);
1633    }
1634
1635    #[test]
1636    fn test_attestation_report_fields() {
1637        let report: AttestationReport = AttestationReport {
1638            version: 2,
1639            guest_svn: 1,
1640            vmpl: 3,
1641            ..Default::default()
1642        };
1643        assert_eq!(report.version, 2);
1644        assert_eq!(report.guest_svn, 1);
1645        assert_eq!(report.vmpl, 3);
1646        assert_eq!(report.measurement, [0; 48]);
1647    }
1648
1649    #[test]
1650    fn test_guest_policy_combined_fields() {
1651        let mut policy: GuestPolicy = Default::default();
1652
1653        policy.set_abi_major(2);
1654        policy.set_abi_minor(1);
1655        policy.set_smt_allowed(true);
1656        policy.set_debug_allowed(true);
1657
1658        assert_eq!(policy.abi_major(), 2);
1659        assert_eq!(policy.abi_minor(), 1);
1660        assert!(policy.smt_allowed());
1661        assert!(policy.debug_allowed());
1662
1663        let policy_u64: u64 = policy.into();
1664        assert_eq!(policy_u64 & (1 << 17), 1 << 17); // Reserved bit 17 must be 1
1665    }
1666
1667    #[test]
1668    fn test_version_display() {
1669        let version = Version::new(3, 2, 1);
1670        assert_eq!(version.to_string(), "3.2.1");
1671
1672        let max_version = Version::new(255, 255, 255);
1673        assert_eq!(max_version.to_string(), "255.255.255");
1674
1675        let min_version = Version::new(0, 0, 0);
1676        assert_eq!(min_version.to_string(), "0.0.0");
1677    }
1678
1679    #[test]
1680    fn test_version_byte_parser() {
1681        // Test from_bytes
1682        let bytes = [1, 2, 3];
1683        let version = Version::from_bytes(&bytes).unwrap();
1684        assert_eq!(version, Version::new(3, 2, 1));
1685
1686        // Test to_bytes
1687        let version = Version::new(4, 5, 6);
1688        let bytes = version.to_bytes().unwrap();
1689        assert_eq!(bytes, [6, 5, 4]);
1690
1691        // Test roundtrip
1692        let original = Version::new(7, 8, 9);
1693        let bytes = original.to_bytes().unwrap();
1694        let roundtrip = Version::from_bytes(&bytes).unwrap();
1695        assert_eq!(original, roundtrip);
1696
1697        // Test default
1698        assert_eq!(<Version as Default>::default(), Version::new(0, 0, 0));
1699    }
1700
1701    #[test]
1702    fn test_attestation_report_from_bytes() {
1703        // Create a valid attestation report bytes minus one byte.
1704        let mut bytes: Vec<u8> = vec![0; 1183];
1705
1706        // Push the version byte at the beginning.
1707        bytes.insert(0, 2);
1708
1709        let vcek = [
1710            0xD4, 0x95, 0x54, 0xEC, 0x71, 0x7F, 0x4E, 0x5B, 0x0F, 0xE6, 0xB1, 0x43, 0xBC, 0xF0,
1711            0x40, 0x5B, 0xD7, 0xAE, 0x30, 0x47, 0x27, 0xED, 0xF4, 0x66, 0x03, 0xF2, 0xA7, 0x6A,
1712            0xEF, 0x6A, 0x3A, 0xBC, 0x15, 0xD7, 0xAF, 0x38, 0xDB, 0x75, 0x70, 0x39, 0x02, 0x9F,
1713            0x0E, 0xFA, 0xCF, 0xD0, 0x8E, 0x24, 0x43, 0x24, 0x88, 0x47, 0x38, 0xC7, 0x2B, 0x08,
1714            0x2E, 0x2F, 0x87, 0xA4, 0x4D, 0x54, 0x1E, 0xB6,
1715        ];
1716
1717        bytes[0x1A8..0x1E0].copy_from_slice(&vcek[..(0x1E0 - 0x1A8)]);
1718
1719        // Test valid input
1720        let result = AttestationReport::from_bytes(bytes.as_slice());
1721        assert!(result.is_ok());
1722    }
1723
1724    #[test]
1725    #[should_panic]
1726    fn test_attestation_report_from_invalid_bytes() {
1727        // Create a valid attestation report bytes minus one byte.
1728        let mut bytes: Vec<u8> = vec![0; 1183];
1729
1730        // Push the version byte at the beginning.
1731        bytes.insert(0, 2);
1732
1733        // Test invalid input (too short)
1734        AttestationReport::from_bytes(bytes[..100].try_into().unwrap()).unwrap();
1735    }
1736
1737    #[test]
1738    fn test_attestation_report_parse_and_write_bytes() {
1739        let report = AttestationReport {
1740            version: 2,
1741            guest_svn: Default::default(),
1742            policy: Default::default(),
1743            family_id: Default::default(),
1744            image_id: Default::default(),
1745            chip_id: [
1746                0xD4, 0x95, 0x54, 0xEC, 0x71, 0x7F, 0x4E, 0x5B, 0x0F, 0xE6, 0xB1, 0x43, 0xBC, 0xF0,
1747                0x40, 0x5B, 0xD7, 0xAE, 0x30, 0x47, 0x27, 0xED, 0xF4, 0x66, 0x03, 0xF2, 0xA7, 0x6A,
1748                0xEF, 0x6A, 0x3A, 0xBC, 0x15, 0xD7, 0xAF, 0x38, 0xDB, 0x75, 0x70, 0x39, 0x02, 0x9F,
1749                0x0E, 0xFA, 0xCF, 0xD0, 0x8E, 0x24, 0x43, 0x24, 0x88, 0x47, 0x38, 0xC7, 0x2B, 0x08,
1750                0x2E, 0x2F, 0x87, 0xA4, 0x4D, 0x54, 0x1E, 0xB6,
1751            ],
1752            ..Default::default()
1753        };
1754
1755        // Test successful write
1756        let result = report.to_bytes();
1757        assert!(result.is_ok());
1758
1759        // Test writing to a failing writer
1760        struct FailingWriter;
1761        impl Write for FailingWriter {
1762            fn write(&mut self, _buf: &[u8]) -> std::io::Result<usize> {
1763                Err(std::io::Error::other("test error"))
1764            }
1765            fn flush(&mut self) -> std::io::Result<()> {
1766                Ok(())
1767            }
1768        }
1769
1770        let mut writer = FailingWriter;
1771
1772        let result = report.encode(&mut FailingWriter, ());
1773        assert!(result.is_err());
1774        assert!(writer.flush().is_ok());
1775    }
1776
1777    #[test]
1778    fn test_version_edge_cases() {
1779        // Test max values
1780        let version = Version::new(255, 255, 255);
1781        let bytes = version.to_bytes().unwrap();
1782        assert_eq!(bytes, [255, 255, 255]);
1783
1784        // Test mixed values
1785        let version = Version::new(0, 255, 0);
1786        let bytes = version.to_bytes().unwrap();
1787        assert_eq!(bytes, [0, 255, 0]);
1788    }
1789
1790    #[test]
1791    fn test_version_ordering() {
1792        let v1 = Version::new(1, 0, 0);
1793        let v2 = Version::new(1, 0, 1);
1794        let v3 = Version::new(1, 1, 0);
1795
1796        assert!(v1 < v2);
1797        assert!(v2 < v3);
1798        assert!(v1 < v3);
1799
1800        // Test equality
1801        assert_eq!(Version::new(1, 2, 3), Version::new(1, 2, 3));
1802        assert_ne!(Version::new(1, 2, 3), Version::new(1, 2, 4));
1803    }
1804
1805    #[test]
1806    fn test_version_copy() {
1807        let original = Version::new(1, 2, 3);
1808        let cloned = original;
1809
1810        assert_eq!(original, cloned);
1811        assert_eq!(original.to_bytes().unwrap(), cloned.to_bytes().unwrap());
1812    }
1813
1814    #[test]
1815    fn test_attestation_report_complex_write() {
1816        let report = AttestationReport {
1817            version: 2,
1818            guest_svn: 1,
1819            policy: GuestPolicy::from(0xFF),
1820            family_id: [0xAA; 16],
1821            image_id: [0xBB; 16],
1822            chip_id: [
1823                0xD4, 0x95, 0x54, 0xEC, 0x71, 0x7F, 0x4E, 0x5B, 0x0F, 0xE6, 0xB1, 0x43, 0xBC, 0xF0,
1824                0x40, 0x5B, 0xD7, 0xAE, 0x30, 0x47, 0x27, 0xED, 0xF4, 0x66, 0x03, 0xF2, 0xA7, 0x6A,
1825                0xEF, 0x6A, 0x3A, 0xBC, 0x15, 0xD7, 0xAF, 0x38, 0xDB, 0x75, 0x70, 0x39, 0x02, 0x9F,
1826                0x0E, 0xFA, 0xCF, 0xD0, 0x8E, 0x24, 0x43, 0x24, 0x88, 0x47, 0x38, 0xC7, 0x2B, 0x08,
1827                0x2E, 0x2F, 0x87, 0xA4, 0x4D, 0x54, 0x1E, 0xB6,
1828            ],
1829            ..Default::default()
1830        };
1831
1832        let buffer = report.to_bytes();
1833        assert!(buffer.is_ok());
1834
1835        // Read back and verify
1836        let read_back = AttestationReport::from_bytes(&buffer.unwrap()).unwrap();
1837        assert_eq!(read_back.version, 2);
1838        assert_eq!(read_back.guest_svn, 1);
1839        assert_eq!(read_back.family_id, [0xAA; 16]);
1840        assert_eq!(read_back.image_id, [0xBB; 16]);
1841    }
1842
1843    #[test]
1844    fn test_write_with_limited_writer() {
1845        let report = AttestationReport {
1846            version: 2,
1847            guest_svn: Default::default(),
1848            policy: Default::default(),
1849            family_id: Default::default(),
1850            image_id: Default::default(),
1851            chip_id: [
1852                0xD4, 0x95, 0x54, 0xEC, 0x71, 0x7F, 0x4E, 0x5B, 0x0F, 0xE6, 0xB1, 0x43, 0xBC, 0xF0,
1853                0x40, 0x5B, 0xD7, 0xAE, 0x30, 0x47, 0x27, 0xED, 0xF4, 0x66, 0x03, 0xF2, 0xA7, 0x6A,
1854                0xEF, 0x6A, 0x3A, 0xBC, 0x15, 0xD7, 0xAF, 0x38, 0xDB, 0x75, 0x70, 0x39, 0x02, 0x9F,
1855                0x0E, 0xFA, 0xCF, 0xD0, 0x8E, 0x24, 0x43, 0x24, 0x88, 0x47, 0x38, 0xC7, 0x2B, 0x08,
1856                0x2E, 0x2F, 0x87, 0xA4, 0x4D, 0x54, 0x1E, 0xB6,
1857            ],
1858            ..Default::default()
1859        };
1860
1861        // Writer that can only write small chunks
1862        struct LimitedWriter {
1863            data: Vec<u8>,
1864            max_write: usize,
1865        }
1866
1867        impl Write for LimitedWriter {
1868            fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
1869                let write_size = std::cmp::min(self.max_write, buf.len());
1870                self.data.extend_from_slice(&buf[..write_size]);
1871                Ok(write_size)
1872            }
1873
1874            fn flush(&mut self) -> std::io::Result<()> {
1875                Ok(())
1876            }
1877        }
1878
1879        let mut writer = LimitedWriter {
1880            data: Vec::new(),
1881            max_write: 16, // Only write 16 bytes at a time
1882        };
1883
1884        assert!(report.encode(&mut writer, ()).is_ok());
1885        assert!(writer.flush().is_ok());
1886    }
1887
1888    #[test]
1889    fn test_platform_v2_info_from_u64() {
1890        let value: u64 = 0xFFFF;
1891        let platform_info = PlatformInfo::from(value);
1892        assert_eq!(platform_info.0, value);
1893
1894        let value: u64 = 0;
1895        let platform_info = PlatformInfo::from(value);
1896        assert_eq!(platform_info.0, value);
1897
1898        let value: u64 = u64::MAX;
1899        let platform_info = PlatformInfo::from(value);
1900        assert_eq!(platform_info.0, value);
1901    }
1902
1903    #[test]
1904    fn test_platform_v2_info_into_u64() {
1905        let platform_info = PlatformInfo(0xFFFF);
1906        let value: u64 = platform_info.into();
1907        assert_eq!(value, 0xFFFF);
1908
1909        let platform_info = PlatformInfo(0);
1910        let value: u64 = platform_info.into();
1911        assert_eq!(value, 0);
1912
1913        let platform_info = PlatformInfo(u64::MAX);
1914        let value: u64 = platform_info.into();
1915        assert_eq!(value, u64::MAX);
1916    }
1917
1918    #[test]
1919    fn test_key_info_from_u32() {
1920        let value: u32 = 0xFFFF;
1921        let key_info = KeyInfo::from(value);
1922        assert_eq!(key_info.0, value);
1923
1924        let value: u32 = 0;
1925        let key_info = KeyInfo::from(value);
1926        assert_eq!(key_info.0, value);
1927
1928        let value: u32 = u32::MAX;
1929        let key_info = KeyInfo::from(value);
1930        assert_eq!(key_info.0, value);
1931    }
1932
1933    #[test]
1934    fn test_key_info_into_u32() {
1935        let key_info = KeyInfo(0xFFFF);
1936        let value: u32 = key_info.into();
1937        assert_eq!(value, 0xFFFF);
1938
1939        let key_info = KeyInfo(0);
1940        let value: u32 = key_info.into();
1941        assert_eq!(value, 0);
1942
1943        let key_info = KeyInfo(u32::MAX);
1944        let value: u32 = key_info.into();
1945        assert_eq!(value, u32::MAX);
1946    }
1947
1948    #[test]
1949    fn test_turin_like_chip_id_milan_chip_id() {
1950        // Valid Milan CHIP_ID
1951        let vcek_bytes = [
1952            0xD4, 0x95, 0x54, 0xEC, 0x71, 0x7F, 0x4E, 0x5B, 0x0F, 0xE6, 0xB1, 0x43, 0xBC, 0xF0,
1953            0x40, 0x5B, 0xD7, 0xAE, 0x30, 0x47, 0x27, 0xED, 0xF4, 0x66, 0x03, 0xF2, 0xA7, 0x6A,
1954            0xEF, 0x6A, 0x3A, 0xBC, 0x15, 0xD7, 0xAF, 0x38, 0xDB, 0x75, 0x70, 0x39, 0x02, 0x9F,
1955            0x0E, 0xFA, 0xCF, 0xD0, 0x8E, 0x24, 0x43, 0x24, 0x88, 0x47, 0x38, 0xC7, 0x2B, 0x08,
1956            0x2E, 0x2F, 0x87, 0xA4, 0x4D, 0x54, 0x1E, 0xB6,
1957        ];
1958
1959        assert!(!AttestationReport::chip_id_is_turin_like(&vcek_bytes).unwrap());
1960    }
1961
1962    #[test]
1963    fn test_turin_like_chip_id_turin_chip_id() {
1964        // Valid Turin CHIP_ID
1965        let vcek_bytes = [
1966            0xD4, 0x95, 0x54, 0xEC, 0x71, 0x7F, 0x4E, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1967            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1968            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1969            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1970            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1971        ];
1972
1973        assert!(AttestationReport::chip_id_is_turin_like(&vcek_bytes).unwrap());
1974    }
1975}