1use 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#[repr(C)]
32#[derive(PartialEq, Debug)]
33pub struct ReportReq {
34 pub data: [u8; 64],
36 pub mnonce: [u8; 16],
38 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#[repr(C)]
81#[derive(PartialEq, Debug)]
82pub struct ReportReqExt {
83 pub data: [u8; 64],
85 pub mnonce: [u8; 16],
87 pub hash: [u8; 32],
89 pub magic: [u8; 16],
91 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#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
138pub struct AttestationReportWrapper {
139 magic: [u8; 16],
141 flags: u32,
144 #[serde(with = "BigArray")]
145 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#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
172pub enum AttestationReport {
173 V1(AttestationReportV1),
175 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 pub fn version(&self) -> u32 {
207 match self {
208 Self::V1(_) => 1,
209 Self::V2(_) => 2,
210 }
211 }
212
213 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 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#[repr(C)]
235#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
236pub struct AttestationReportV1 {
237 pub tee_info: TeeInfoV1,
239 pub signer: TeeInfoSigner,
241 #[serde(with = "BigArray")]
242 reserved:
244 [u8; 4096 - (std::mem::size_of::<TeeInfoV1>() + std::mem::size_of::<TeeInfoSigner>())],
245}
246
247const_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#[repr(C)]
280#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
281pub struct AttestationReportV2 {
282 pub tee_info: TeeInfoV2,
284 pub signer: TeeInfoSigner,
286 #[serde(with = "BigArray")]
288 reserved:
289 [u8; 4096 - (std::mem::size_of::<TeeInfoV2>() + std::mem::size_of::<TeeInfoSigner>())],
290}
291
292const_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
319pub enum TeeInfo<'a> {
328 V1(&'a TeeInfoV1),
330 V2(&'a TeeInfoV2),
332}
333
334impl TeeInfo<'_> {
335 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 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 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 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 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 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 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 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 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 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 pub fn anonce(&self) -> u32 {
422 match *self {
423 Self::V1(tee_info) => tee_info.anonce,
424 Self::V2(_) => 0,
425 }
426 }
427
428 pub fn build(&self) -> u32 {
430 match *self {
431 Self::V1(_) => 0,
432 Self::V2(tee_info) => tee_info.build,
433 }
434 }
435
436 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 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 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 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 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 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#[repr(C)]
539#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
540pub struct TeeInfoV1 {
541 pub user_pubkey_digest: [u8; 32],
544 pub vm_id: [u8; 16],
546 pub vm_version: [u8; 16],
548 #[serde(with = "BigArray")]
549 pub report_data: [u8; 64],
551 pub mnonce: [u8; 16],
553 pub measure: [u8; 32],
555 pub policy: GuestPolicy,
557 pub sig_usage: u32,
559 pub sig_algo: u32,
561 pub anonce: u32,
563 pub sig: ecdsa::Signature,
572}
573
574const_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#[repr(C)]
613#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
614pub struct TeeInfoV2 {
615 pub user_pubkey_digest: [u8; 32],
618 pub vm_id: [u8; 16],
620 pub vm_version: [u8; 16],
622 #[serde(with = "BigArray")]
623 pub report_data: [u8; 64],
625 pub mnonce: [u8; 16],
627 pub measure: [u8; 32],
629 pub policy: GuestPolicy,
631 pub sig_usage: u32,
633 pub sig_algo: u32,
635 pub build: u32,
637 pub rtmr_version: u16,
639 pub reserved0: [u8; 14],
641 pub rtmr0: [u8; CSV_RTMR_REG_SIZE],
643 pub rtmr1: [u8; CSV_RTMR_REG_SIZE],
645 pub rtmr2: [u8; CSV_RTMR_REG_SIZE],
647 pub rtmr3: [u8; CSV_RTMR_REG_SIZE],
649 pub rtmr4: [u8; CSV_RTMR_REG_SIZE],
651 #[serde(with = "BigArray")]
652 pub reserved1: [u8; 656],
654 pub sig: ecdsa::Signature,
674}
675
676const_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 #[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 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 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 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}