1#![cfg_attr(not(feature = "std"), no_std)]
3
4#[cfg(feature = "alloc")]
7extern crate alloc;
8
9mod error;
10mod hash_algorithm;
11
12pub use error::{KbsTypesError, Result};
13pub use hash_algorithm::HashAlgorithm;
14
15#[cfg(all(feature = "alloc", not(feature = "std")))]
16use alloc::{string::String, vec::Vec};
17use base64::{prelude::BASE64_URL_SAFE_NO_PAD, Engine};
18#[cfg(feature = "std")]
19use ear::{self, RawValue};
20use serde::{Deserialize, Serialize};
21use serde_json::{Map, Value};
22#[cfg(all(feature = "std", not(feature = "alloc")))]
23use std::string::String;
24
25use strum::{AsRefStr, Display, EnumString};
26
27#[derive(
28 Serialize, Clone, Copy, Deserialize, Debug, Eq, Hash, PartialEq, AsRefStr, Display, EnumString,
29)]
30#[serde(rename_all = "lowercase")]
31pub enum Tee {
32 #[serde(rename = "az-snp-vtpm")]
34 #[strum(serialize = "az-snp-vtpm")]
35 AzSnpVtpm,
36 #[serde(rename = "az-tdx-vtpm")]
37 #[strum(serialize = "az-tdx-vtpm")]
38 AzTdxVtpm,
39 #[strum(serialize = "nvidia")]
40 Nvidia,
41 #[strum(serialize = "sgx")]
42 Sgx,
43 #[strum(serialize = "snp")]
44 Snp,
45 #[strum(serialize = "tdx")]
46 Tdx,
47 #[strum(serialize = "cca")]
49 Cca,
50 #[strum(serialize = "csv")]
52 Csv,
53 #[strum(serialize = "se")]
55 Se,
56
57 #[strum(serialize = "hygondcu")]
59 HygonDcu,
60
61 #[serde(rename = "nvidia-dpu", alias = "nvidiadpu")]
63 #[strum(to_string = "nvidia-dpu", serialize = "nvidiadpu")]
64 NvidiaDpu,
65
66 #[strum(serialize = "tpm")]
68 Tpm,
69
70 #[strum(serialize = "sample")]
73 Sample,
74 #[strum(serialize = "sampledevice")]
75 SampleDevice,
76}
77
78#[derive(Clone, Serialize, Deserialize, Debug)]
79pub struct Request {
80 pub version: String,
81 pub tee: Tee,
82 #[serde(rename = "extra-params")]
83 pub extra_params: Value,
84}
85
86#[derive(Clone, Serialize, Deserialize, Debug)]
87pub struct Challenge {
88 pub nonce: String,
89 #[serde(rename = "extra-params")]
90 pub extra_params: Value,
91}
92
93#[derive(Clone, Serialize, Deserialize, Debug)]
94#[serde(tag = "kty")]
95pub enum TeePubKey {
96 RSA {
97 alg: String,
98 #[serde(rename = "n")]
99 k_mod: String,
100 #[serde(rename = "e")]
101 k_exp: String,
102 },
103 EC {
107 crv: String,
108 alg: String,
109 x: String,
110 y: String,
111 },
112 AKP {
115 alg: String,
116 #[serde(rename = "pub")]
117 public_key: String,
118 },
119}
120
121#[cfg(feature = "std")]
122impl From<&TeePubKey> for ear::RawValue {
123 fn from(tpk: &TeePubKey) -> RawValue {
124 let mut map: Vec<(RawValue, RawValue)> = vec![];
125
126 match tpk {
127 TeePubKey::RSA { alg, k_mod, k_exp } => {
128 map.push((
129 RawValue::String("kty".to_string()),
130 RawValue::String("RSA".to_string()),
131 ));
132 map.push((
133 RawValue::String("alg".to_string()),
134 RawValue::String(alg.clone()),
135 ));
136 map.push((
137 RawValue::String("n".to_string()),
138 RawValue::String(k_mod.clone()),
139 ));
140 map.push((
141 RawValue::String("e".to_string()),
142 RawValue::String(k_exp.clone()),
143 ));
144 }
145 TeePubKey::EC { crv, alg, x, y } => {
146 map.push((
147 RawValue::String("kty".to_string()),
148 RawValue::String("EC".to_string()),
149 ));
150 map.push((
151 RawValue::String("crv".to_string()),
152 RawValue::String(crv.clone()),
153 ));
154 map.push((
155 RawValue::String("alg".to_string()),
156 RawValue::String(alg.clone()),
157 ));
158 map.push((
159 RawValue::String("x".to_string()),
160 RawValue::String(x.clone()),
161 ));
162 map.push((
163 RawValue::String("y".to_string()),
164 RawValue::String(y.clone()),
165 ));
166 }
167 TeePubKey::AKP { alg, public_key } => {
168 map.push((
169 RawValue::String("kty".to_string()),
170 RawValue::String("AKP".to_string()),
171 ));
172 map.push((
173 RawValue::String("alg".to_string()),
174 RawValue::String(alg.clone()),
175 ));
176 map.push((
177 RawValue::String("pub".to_string()),
178 RawValue::String(public_key.clone()),
179 ));
180 }
181 }
182
183 RawValue::Map(map)
184 }
185}
186
187#[derive(Clone, Debug, Deserialize, Serialize)]
190pub struct RuntimeData {
191 pub nonce: String,
193
194 #[serde(rename = "tee-pubkey")]
196 pub tee_pubkey: TeePubKey,
197}
198
199#[derive(Clone, Debug, Deserialize, Serialize)]
201pub struct CompositeEvidence {
202 pub primary_evidence: Value,
204
205 pub additional_evidence: String,
211}
212
213#[derive(Clone, Debug, Deserialize, Serialize)]
215pub struct InitData {
216 pub format: String,
218
219 pub body: String,
221}
222
223#[derive(Clone, Serialize, Deserialize, Debug)]
224#[serde(rename_all = "kebab-case")]
225pub struct Attestation {
226 pub init_data: Option<InitData>,
227 pub runtime_data: RuntimeData,
228 pub tee_evidence: CompositeEvidence,
229}
230
231#[derive(Clone, Serialize, Deserialize, Debug)]
232pub struct ProtectedHeader {
233 pub alg: String,
235 pub enc: String,
237
238 #[serde(skip_serializing_if = "Map::is_empty", flatten)]
240 pub other_fields: Map<String, Value>,
241}
242
243impl ProtectedHeader {
244 pub fn generate_aad(&self) -> Result<Vec<u8>> {
246 let protected_utf8 = serde_json::to_string(&self).map_err(|_| KbsTypesError::Serde)?;
247 let aad = BASE64_URL_SAFE_NO_PAD.encode(protected_utf8);
248 Ok(aad.into_bytes())
249 }
250}
251
252fn serialize_base64_protected_header<S>(
253 sub: &ProtectedHeader,
254 serializer: S,
255) -> core::result::Result<S::Ok, S::Error>
256where
257 S: serde::Serializer,
258{
259 let protected_header_json = serde_json::to_string(sub).map_err(serde::ser::Error::custom)?;
260 let encoded = BASE64_URL_SAFE_NO_PAD.encode(protected_header_json);
261 serializer.serialize_str(&encoded)
262}
263
264fn deserialize_base64_protected_header<'de, D>(
265 deserializer: D,
266) -> core::result::Result<ProtectedHeader, D::Error>
267where
268 D: serde::Deserializer<'de>,
269{
270 let encoded = String::deserialize(deserializer)?;
271 let decoded = BASE64_URL_SAFE_NO_PAD
272 .decode(encoded)
273 .map_err(serde::de::Error::custom)?;
274 let protected_header = serde_json::from_slice(&decoded).map_err(serde::de::Error::custom)?;
275
276 Ok(protected_header)
277}
278
279fn serialize_base64<S>(sub: &Vec<u8>, serializer: S) -> core::result::Result<S::Ok, S::Error>
280where
281 S: serde::Serializer,
282{
283 let encoded = BASE64_URL_SAFE_NO_PAD.encode(sub);
284 serializer.serialize_str(&encoded)
285}
286
287fn deserialize_base64<'de, D>(deserializer: D) -> core::result::Result<Vec<u8>, D::Error>
288where
289 D: serde::Deserializer<'de>,
290{
291 let encoded = String::deserialize(deserializer)?;
292 let decoded = BASE64_URL_SAFE_NO_PAD
293 .decode(encoded)
294 .map_err(serde::de::Error::custom)?;
295
296 Ok(decoded)
297}
298
299fn serialize_base64_vec<S>(
300 sub: &Option<Vec<u8>>,
301 serializer: S,
302) -> core::result::Result<S::Ok, S::Error>
303where
304 S: serde::Serializer,
305{
306 match sub {
307 Some(value) => {
308 let encoded = String::from_utf8(value.clone()).map_err(serde::ser::Error::custom)?;
309 serializer.serialize_str(&encoded)
310 }
311 None => serializer.serialize_none(),
312 }
313}
314
315fn deserialize_base64_vec<'de, D>(
316 deserializer: D,
317) -> core::result::Result<Option<Vec<u8>>, D::Error>
318where
319 D: serde::Deserializer<'de>,
320{
321 let string = String::deserialize(deserializer)?;
322 let bytes = string.into_bytes();
323
324 Ok(Some(bytes))
325}
326
327#[derive(Clone, Serialize, Deserialize, Debug)]
328pub struct Response {
329 #[serde(
330 serialize_with = "serialize_base64_protected_header",
331 deserialize_with = "deserialize_base64_protected_header"
332 )]
333 pub protected: ProtectedHeader,
334
335 #[serde(
336 serialize_with = "serialize_base64",
337 deserialize_with = "deserialize_base64"
338 )]
339 pub encrypted_key: Vec<u8>,
340
341 #[serde(
342 skip_serializing_if = "Option::is_none",
343 default = "Option::default",
344 serialize_with = "serialize_base64_vec",
345 deserialize_with = "deserialize_base64_vec"
346 )]
347 pub aad: Option<Vec<u8>>,
348
349 #[serde(
350 serialize_with = "serialize_base64",
351 deserialize_with = "deserialize_base64"
352 )]
353 pub iv: Vec<u8>,
354
355 #[serde(
356 serialize_with = "serialize_base64",
357 deserialize_with = "deserialize_base64"
358 )]
359 pub ciphertext: Vec<u8>,
360
361 #[serde(
362 serialize_with = "serialize_base64",
363 deserialize_with = "deserialize_base64"
364 )]
365 pub tag: Vec<u8>,
366}
367
368#[derive(Clone, Serialize, Deserialize, Debug)]
369pub struct ErrorInformation {
370 #[serde(rename = "type")]
371 pub error_type: String,
372 pub detail: String,
373}
374
375#[cfg(test)]
376mod tests {
377 use serde_json::json;
378
379 use crate::*;
380
381 #[cfg(all(feature = "alloc", not(feature = "std")))]
382 use alloc::string::ToString;
383
384 #[test]
385 fn parse_request() {
386 let data = r#"
387 {
388 "version": "0.0.0",
389 "tee": "tdx",
390 "extra-params": ""
391 }"#;
392
393 let request: Request = serde_json::from_str(data).unwrap();
394
395 assert_eq!(request.version, "0.0.0");
396 assert_eq!(request.tee, Tee::Tdx);
397 assert_eq!(request.extra_params, "");
398 }
399
400 #[test]
401 fn parse_challenge() {
402 let data = r#"
403 {
404 "nonce": "42",
405 "extra-params": ""
406 }"#;
407
408 let challenge: Challenge = serde_json::from_str(data).unwrap();
409
410 assert_eq!(challenge.nonce, "42");
411 assert_eq!(challenge.extra_params, "");
412 }
413
414 #[test]
415 fn protected_header_generate_aad() {
416 let protected_header = ProtectedHeader {
417 alg: "fakealg".to_string(),
418 enc: "fakeenc".to_string(),
419 other_fields: Map::new(),
420 };
421
422 let aad = protected_header.generate_aad().unwrap();
423
424 assert_eq!(
425 aad,
426 "eyJhbGciOiJmYWtlYWxnIiwiZW5jIjoiZmFrZWVuYyJ9".as_bytes()
427 );
428 }
429
430 #[test]
431 fn parse_response() {
432 let data = r#"
433 {
434 "protected": "eyJhbGciOiJmYWtlYWxnIiwiZW5jIjoiZmFrZWVuYyJ9",
435 "encrypted_key": "ZmFrZWtleQ",
436 "iv": "cmFuZG9tZGF0YQ",
437 "ciphertext": "ZmFrZWVuY291dHB1dA",
438 "tag": "ZmFrZXRhZw"
439 }"#;
440
441 let response: Response = serde_json::from_str(data).unwrap();
442
443 assert_eq!(response.protected.alg, "fakealg");
444 assert_eq!(response.protected.enc, "fakeenc");
445 assert!(response.protected.other_fields.is_empty());
446 assert_eq!(response.encrypted_key, "fakekey".as_bytes());
447 assert_eq!(response.iv, "randomdata".as_bytes());
448 assert_eq!(response.ciphertext, "fakeencoutput".as_bytes());
449 assert_eq!(response.tag, "faketag".as_bytes());
450 assert_eq!(response.aad, None);
451 }
452
453 #[test]
454 fn parse_response_nested_protected_header() {
455 let data = r#"
456 {
457 "protected": "eyJhbGciOiJmYWtlYWxnIiwiZW5jIjoiZmFrZWVuYyIsImVwayI6eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ4IjoiaFNEd0NZa3dwMVIwaTMzY3RENzNXZzJfT2cwbU9CcjA2NlNwanFxYlRtbyJ9fQo",
458 "encrypted_key": "ZmFrZWtleQ",
459 "iv": "cmFuZG9tZGF0YQ",
460 "ciphertext": "ZmFrZWVuY291dHB1dA",
461 "tag": "ZmFrZXRhZw"
462 }"#;
463
464 let response: Response = serde_json::from_str(data).unwrap();
465
466 assert_eq!(response.protected.alg, "fakealg");
467 assert_eq!(response.protected.enc, "fakeenc");
468
469 let expected_other_fields = json!({
470 "epk": {
471 "kty" : "OKP",
472 "crv": "X25519",
473 "x": "hSDwCYkwp1R0i33ctD73Wg2_Og0mOBr066SpjqqbTmo"
474 }
475 })
476 .as_object()
477 .unwrap()
478 .clone();
479
480 assert_eq!(response.protected.other_fields, expected_other_fields);
481 assert_eq!(response.encrypted_key, "fakekey".as_bytes());
482 assert_eq!(response.iv, "randomdata".as_bytes());
483 assert_eq!(response.ciphertext, "fakeencoutput".as_bytes());
484 assert_eq!(response.tag, "faketag".as_bytes());
485 assert_eq!(response.aad, None);
486 }
487
488 #[test]
489 fn parse_response_with_aad() {
490 let data = r#"
491 {
492 "protected": "eyJhbGciOiJmYWtlYWxnIiwiZW5jIjoiZmFrZWVuYyJ9Cg",
493 "encrypted_key": "ZmFrZWtleQ",
494 "iv": "cmFuZG9tZGF0YQ",
495 "aad": "fakeaad",
496 "ciphertext": "ZmFrZWVuY291dHB1dA",
497 "tag": "ZmFrZXRhZw"
498 }"#;
499
500 let response: Response = serde_json::from_str(data).unwrap();
501
502 assert_eq!(response.protected.alg, "fakealg");
503 assert_eq!(response.protected.enc, "fakeenc");
504 assert!(response.protected.other_fields.is_empty());
505 assert_eq!(response.encrypted_key, "fakekey".as_bytes());
506 assert_eq!(response.iv, "randomdata".as_bytes());
507 assert_eq!(response.ciphertext, "fakeencoutput".as_bytes());
508 assert_eq!(response.tag, "faketag".as_bytes());
509 assert_eq!(response.aad, Some("fakeaad".into()));
510 }
511
512 #[test]
513 fn parse_response_with_protectedheader() {
514 let data = r#"
515 {
516 "protected": "eyJhbGciOiJmYWtlYWxnIiwiZW5jIjoiZmFrZWVuYyIsImZha2VmaWVsZCI6ImZha2V2YWx1ZSJ9",
517 "encrypted_key": "ZmFrZWtleQ",
518 "iv": "cmFuZG9tZGF0YQ",
519 "aad": "fakeaad",
520 "ciphertext": "ZmFrZWVuY291dHB1dA",
521 "tag": "ZmFrZXRhZw"
522 }"#;
523
524 let response: Response = serde_json::from_str(data).unwrap();
525
526 assert_eq!(response.protected.alg, "fakealg");
527 assert_eq!(response.protected.enc, "fakeenc");
528 assert_eq!(response.protected.other_fields["fakefield"], "fakevalue");
529 assert_eq!(response.encrypted_key, "fakekey".as_bytes());
530 assert_eq!(response.iv, "randomdata".as_bytes());
531 assert_eq!(response.ciphertext, "fakeencoutput".as_bytes());
532 assert_eq!(response.tag, "faketag".as_bytes());
533 assert_eq!(response.aad, Some("fakeaad".into()));
534 }
535
536 #[test]
537 fn serialize_response() {
538 let response = Response {
539 protected: ProtectedHeader {
540 alg: "fakealg".into(),
541 enc: "fakeenc".into(),
542 other_fields: [("fakefield".into(), "fakevalue".into())]
543 .into_iter()
544 .collect(),
545 },
546 encrypted_key: "fakekey".as_bytes().to_vec(),
547 iv: "randomdata".as_bytes().to_vec(),
548 aad: Some("fakeaad".into()),
549 tag: "faketag".as_bytes().to_vec(),
550 ciphertext: "fakeencoutput".as_bytes().to_vec(),
551 };
552
553 let expected = json!({
554 "protected": "eyJhbGciOiJmYWtlYWxnIiwiZW5jIjoiZmFrZWVuYyIsImZha2VmaWVsZCI6ImZha2V2YWx1ZSJ9",
555 "encrypted_key": "ZmFrZWtleQ",
556 "iv": "cmFuZG9tZGF0YQ",
557 "aad": "fakeaad",
558 "ciphertext": "ZmFrZWVuY291dHB1dA",
559 "tag": "ZmFrZXRhZw"
560 });
561
562 let serialized = serde_json::to_value(&response).unwrap();
563 assert_eq!(serialized, expected);
564 }
565
566 #[test]
567 fn parse_attestation_ec() {
568 let data = r#"
569 {
570 "runtime-data": {
571 "nonce": "test_nonce",
572 "tee-pubkey": {
573 "kty": "EC",
574 "crv": "fakecrv",
575 "alg": "fakealgorithm",
576 "x": "fakex",
577 "y": "fakey"
578 }
579 },
580 "tee-evidence": {
581 "primary_evidence": "test_primary_evidence",
582 "additional_evidence": "test_additional_evidence"
583 }
584 }"#;
585
586 let attestation: Attestation = serde_json::from_str(data).unwrap();
587 let tee_pubkey = attestation.runtime_data.tee_pubkey;
588
589 let TeePubKey::EC { alg, crv, x, y } = tee_pubkey else {
590 panic!("Must be an EC key");
591 };
592
593 assert_eq!(alg, "fakealgorithm");
594 assert_eq!(crv, "fakecrv");
595 assert_eq!(x, "fakex");
596 assert_eq!(y, "fakey");
597 assert_eq!(
598 attestation.tee_evidence.primary_evidence,
599 "test_primary_evidence"
600 );
601 assert_eq!(
602 attestation.tee_evidence.additional_evidence,
603 "test_additional_evidence"
604 );
605 }
606
607 #[test]
608 fn parse_attestation_rsa() {
609 let data = r#"
610 {
611 "runtime-data": {
612 "nonce": "test_nonce",
613 "tee-pubkey": {
614 "kty": "RSA",
615 "alg": "fakealgorithm",
616 "n": "fakemodulus",
617 "e": "fakeexponent"
618 }
619 },
620 "tee-evidence": {
621 "primary_evidence": "test_primary_evidence",
622 "additional_evidence": "test_additional_evidence"
623 }
624 }"#;
625
626 let attestation: Attestation = serde_json::from_str(data).unwrap();
627 let tee_pubkey = attestation.runtime_data.tee_pubkey;
628
629 let TeePubKey::RSA { alg, k_mod, k_exp } = tee_pubkey else {
630 panic!("Must be a RSA key");
631 };
632
633 assert_eq!(attestation.runtime_data.nonce, "test_nonce");
634 assert_eq!(alg, "fakealgorithm");
635 assert_eq!(k_mod, "fakemodulus");
636 assert_eq!(k_exp, "fakeexponent");
637 assert_eq!(
638 attestation.tee_evidence.primary_evidence,
639 "test_primary_evidence"
640 );
641 assert_eq!(
642 attestation.tee_evidence.additional_evidence,
643 "test_additional_evidence"
644 );
645 }
646
647 #[test]
648 fn parse_attestation_akp() {
649 let data = r#"
650 {
651 "runtime-data": {
652 "nonce": "test_nonce",
653 "tee-pubkey": {
654 "kty": "AKP",
655 "alg": "fakealgorithm",
656 "pub": "fakepublickey"
657 }
658 },
659 "tee-evidence": {
660 "primary_evidence": "test_primary_evidence",
661 "additional_evidence": "test_additional_evidence"
662 }
663 }"#;
664
665 let attestation: Attestation = serde_json::from_str(data).unwrap();
666 let tee_pubkey = attestation.runtime_data.tee_pubkey;
667
668 let TeePubKey::AKP { alg, public_key } = tee_pubkey else {
669 panic!("Must be a AKP key");
670 };
671
672 assert_eq!(attestation.runtime_data.nonce, "test_nonce");
673 assert_eq!(alg, "fakealgorithm");
674 assert_eq!(public_key, "fakepublickey");
675 assert_eq!(
676 attestation.tee_evidence.primary_evidence,
677 "test_primary_evidence"
678 );
679 assert_eq!(
680 attestation.tee_evidence.additional_evidence,
681 "test_additional_evidence"
682 );
683 }
684
685 #[test]
686 fn parse_error_information() {
687 let data = r#"
688 {
689 "type": "problemtype",
690 "detail": "problemdetail"
691 }"#;
692
693 let info: ErrorInformation = serde_json::from_str(data).unwrap();
694
695 assert_eq!(info.error_type, "problemtype");
696 assert_eq!(info.detail, "problemdetail");
697 }
698
699 #[test]
700 #[cfg(feature = "std")]
701 fn tee_pubkey_ear_json_deserialize() {
702 let tpk = TeePubKey::RSA {
704 alg: "test".to_string(),
705 k_mod: "test".to_string(),
706 k_exp: "test".to_string(),
707 };
708 let ear_raw: RawValue = (&tpk).into();
709 let json_str = serde_json::to_string(&ear_raw).unwrap();
710 assert_eq!(json_str, serde_json::to_string(&tpk).unwrap());
711
712 let tpk = TeePubKey::EC {
714 crv: "test".to_string(),
715 alg: "test".to_string(),
716 x: "test".to_string(),
717 y: "test".to_string(),
718 };
719 let ear_raw: RawValue = (&tpk).into();
720 let json_str = serde_json::to_string(&ear_raw).unwrap();
721 assert_eq!(json_str, serde_json::to_string(&tpk).unwrap());
722
723 let tpk = TeePubKey::AKP {
725 alg: "test".to_string(),
726 public_key: "test".to_string(),
727 };
728 let ear_raw: RawValue = (&tpk).into();
729 let json_str = serde_json::to_string(&ear_raw).unwrap();
730 assert_eq!(json_str, serde_json::to_string(&tpk).unwrap());
731 }
732
733 #[test]
734 fn tee_as_ref() {
735 assert_eq!(Tee::AzSnpVtpm.as_ref(), "az-snp-vtpm");
736 assert_eq!(Tee::AzTdxVtpm.as_ref(), "az-tdx-vtpm");
737 assert_eq!(Tee::Nvidia.as_ref(), "nvidia");
738 assert_eq!(Tee::Sgx.as_ref(), "sgx");
739 assert_eq!(Tee::Snp.as_ref(), "snp");
740 assert_eq!(Tee::Tdx.as_ref(), "tdx");
741 assert_eq!(Tee::Cca.as_ref(), "cca");
742 assert_eq!(Tee::Csv.as_ref(), "csv");
743 assert_eq!(Tee::Se.as_ref(), "se");
744 assert_eq!(Tee::HygonDcu.as_ref(), "hygondcu");
745 assert_eq!(Tee::NvidiaDpu.as_ref(), "nvidia-dpu");
746 assert_eq!(Tee::Tpm.as_ref(), "tpm");
747 assert_eq!(Tee::Sample.as_ref(), "sample");
748 assert_eq!(Tee::SampleDevice.as_ref(), "sampledevice");
749 }
750
751 #[cfg(feature = "std")]
752 #[test]
753 fn tee_from_str() {
754 use std::str::FromStr;
755
756 assert_eq!(Tee::from_str("az-snp-vtpm").unwrap(), Tee::AzSnpVtpm);
757 assert_eq!(Tee::from_str("az-tdx-vtpm").unwrap(), Tee::AzTdxVtpm);
758 assert_eq!(Tee::from_str("nvidia").unwrap(), Tee::Nvidia);
759 assert_eq!(Tee::from_str("sgx").unwrap(), Tee::Sgx);
760 assert_eq!(Tee::from_str("snp").unwrap(), Tee::Snp);
761 assert_eq!(Tee::from_str("tdx").unwrap(), Tee::Tdx);
762 assert_eq!(Tee::from_str("cca").unwrap(), Tee::Cca);
763 assert_eq!(Tee::from_str("csv").unwrap(), Tee::Csv);
764 assert_eq!(Tee::from_str("se").unwrap(), Tee::Se);
765 assert_eq!(Tee::from_str("hygondcu").unwrap(), Tee::HygonDcu);
766 assert_eq!(Tee::from_str("nvidia-dpu").unwrap(), Tee::NvidiaDpu);
767 assert_eq!(Tee::from_str("nvidiadpu").unwrap(), Tee::NvidiaDpu);
768 assert_eq!(Tee::from_str("tpm").unwrap(), Tee::Tpm);
769 assert_eq!(Tee::from_str("sample").unwrap(), Tee::Sample);
770 assert_eq!(Tee::from_str("sampledevice").unwrap(), Tee::SampleDevice);
771 Tee::from_str("invalid").unwrap_err();
772 }
773
774 #[test]
775 fn tee_serde_nvidia_dpu_alias() {
776 let serialized = serde_json::to_string(&Tee::NvidiaDpu).unwrap();
778 assert_eq!(serialized, "\"nvidia-dpu\"");
779
780 let deserialized: Tee = serde_json::from_str("\"nvidiadpu\"").unwrap();
782 assert_eq!(deserialized, Tee::NvidiaDpu);
783 }
784}