From cd0dac5d38821837b51150c9c68c8737f09b5773 Mon Sep 17 00:00:00 2001 From: Qi Feng Huo Date: Thu, 16 May 2024 13:24:59 +0800 Subject: [PATCH] Verifier: IBM SE implementation PoC Signed-off-by: Qi Feng Huo --- Cargo.toml | 4 + attestation-service/docs/parsed_claims.md | 7 +- attestation-service/verifier/Cargo.toml | 7 +- attestation-service/verifier/src/se/ibmse.rs | 421 +++++++++++++------ attestation-service/verifier/src/se/mod.rs | 79 ++-- 5 files changed, 353 insertions(+), 165 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4ffba909be..185961561a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ prost = "0.11.0" regorus = { version = "0.1.2", default-features = false, features = ["regex", "base64", "time"] } rstest = "0.18.1" serde = { version = "1.0", features = ["derive"] } +serde_with = { version = "1.11.0", features = ["base64"] } serde_json = "1.0.89" serial_test = "0.9.0" sha2 = "0.10" @@ -48,3 +49,6 @@ tempfile = "3.4.0" tonic = "0.8.1" tonic-build = "0.8.0" +[patch.crates-io] +s390_pv = { path = "/root/src/tmp_pv_crate/rust/pv" } +s390_pv_core = { path = "/root/src/tmp_pv_crate/rust/pv_core" } \ No newline at end of file diff --git a/attestation-service/docs/parsed_claims.md b/attestation-service/docs/parsed_claims.md index be3ac34a14..e2d8d292cd 100644 --- a/attestation-service/docs/parsed_claims.md +++ b/attestation-service/docs/parsed_claims.md @@ -94,4 +94,9 @@ The claim inherit the fields from the SEV-SNP claim with and additional `tpm` hi Note: The TD Report and TD Quote are fetched during early boot in this TEE. Kernel, Initrd and rootfs are measured into the vTPM's registers. ## IBM Secure Execution (SE) -TBD \ No newline at end of file +- `se.version`: The version this quote structure. +- `se.cuid`: The config uid. +- `se.hdr.seht`: SE Header Tag (seht) +- `se.image.phkh`: SE image Public host key hash +- `se.attestation.phkh`: SE attestation Public host key hash +- `se.user_data`: Custom attestation key owner data. diff --git a/attestation-service/verifier/Cargo.toml b/attestation-service/verifier/Cargo.toml index ec33b13503..6a2abf13d9 100644 --- a/attestation-service/verifier/Cargo.toml +++ b/attestation-service/verifier/Cargo.toml @@ -13,7 +13,7 @@ az-tdx-vtpm-verifier = [ "az-tdx-vtpm", "openssl", "tdx-verifier" ] snp-verifier = [ "asn1-rs", "openssl", "sev", "x509-parser" ] csv-verifier = [ "openssl", "csv-rs", "codicon" ] cca-verifier = [ "ear", "jsonwebtoken", "veraison-apiclient" ] -se-verifier = [ "openssl", "pv" ] +se-verifier = [ "openssl" ] [dependencies] anyhow.workspace = true @@ -40,6 +40,7 @@ pv = { version = "0.10.0", package = "s390_pv" } scroll = { version = "0.11.0", default-features = false, features = ["derive"], optional = true } serde.workspace = true serde_json.workspace = true +serde_with.workspace = true serde_yaml = "0.9.0" sev = { version = "1.2.0", features = ["openssl", "snp"], optional = true } sgx-dcap-quoteverify-rs = { git = "https://github.com/intel/SGXDataCenterAttestationPrimitives", tag = "DCAP_1.16", optional = true } @@ -59,5 +60,5 @@ serial_test.workspace = true tokio.workspace = true [patch.crates-io] -s390_pv = { path = "/root/src/tmp_pv_crate/pv" } -s390_pv_core = { path = "/root/src/tmp_pv_crate/pv_core" } +s390_pv = { path = "/root/src/tmp_pv_crate/rust/pv" } +s390_pv_core = { path = "/root/src/tmp_pv_crate/rust/pv_core" } diff --git a/attestation-service/verifier/src/se/ibmse.rs b/attestation-service/verifier/src/se/ibmse.rs index dfc31f1382..5c241ff73e 100644 --- a/attestation-service/verifier/src/se/ibmse.rs +++ b/attestation-service/verifier/src/se/ibmse.rs @@ -3,163 +3,316 @@ // SPDX-License-Identifier: Apache-2.0 // -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{anyhow, Result}; use log::{debug, warn}; +use openssl::{ + encrypt::{Decrypter, Encrypter}, + pkey::{PKey, Private, Public}, + rsa::{Padding, Rsa}, +}; use pv::{ attest::{ AdditionalData, AttestationFlags, AttestationItems, AttestationMeasAlg, - AttestationMeasurement, AttestationRequest, AttestationVersion, ExchangeFormatCtx, - ExchangeFormatVersion, + AttestationMeasurement, AttestationRequest, AttestationVersion, }, - misc::{CertificateOptions, open_file, read_exact_file, write_file, HexSlice}, - request::{openssl::pkey::PKey, BootHdrTags, Confidential, ReqEncrCtx, Request, SymKey, SymKeyType}, + misc::{open_file, read_certs, read_file, HexSlice}, + request::{BootHdrTags, CertVerifier, HkdVerifier, ReqEncrCtx, Request, SymKeyType}, + uv::ConfigUid, }; -use serde::Serialize; -use serde_yaml; -use std::{fmt::Display, io::Read, process::ExitCode}; - -const EXIT_CODE_ATTESTATION_FAIL: u8 = 2; - -#[derive(Serialize)] -struct VerifyOutput<'a> { - cuid: HexSlice<'a>, - #[serde(skip_serializing_if = "Option::is_none")] - additional_data: Option>, - #[serde(skip_serializing_if = "Option::is_none")] - additional_data_fields: Option>>, - #[serde(skip_serializing_if = "Option::is_none")] - user_data: Option>, +use serde::{Deserialize, Serialize}; +use serde_json; +use serde_with::{base64::Base64, serde_as}; +use std::{fs::File, io::Read}; + +fn encrypt_measurement_key(key: &[u8], rsa_public_key: &PKey) -> Vec { + let mut encrypter = Encrypter::new(rsa_public_key).unwrap(); + encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); + + let buffer_len = encrypter.encrypt_len(key).unwrap(); + let mut encrypted_hmac_key = vec![0; buffer_len]; + let len = encrypter.encrypt(key, &mut encrypted_hmac_key).unwrap(); + encrypted_hmac_key.truncate(len); + + encrypted_hmac_key +} + +fn decrypt_measurement_key(key: &[u8], rsa_private_key: &PKey) -> Vec { + let mut decrypter = Decrypter::new(rsa_private_key).unwrap(); + decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); + + let buffer_len = decrypter.decrypt_len(key).unwrap(); + let mut decrypted_hmac_key = vec![0; buffer_len]; + let decrypted_len = decrypter.decrypt(key, &mut decrypted_hmac_key).unwrap(); + decrypted_hmac_key.truncate(decrypted_len); + + decrypted_hmac_key +} + +#[serde_as] +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct UserData { + #[serde_as(as = "Base64")] + image_btph: Vec, } -impl<'a> VerifyOutput<'a> { - fn from_exchange(ctx: &'a ExchangeFormatCtx, flags: &AttestationFlags) -> Result { - let additional_data_fields = ctx - .additional() - .map(|a| AdditionalData::from_slice(a, flags)) - .transpose()?; - let user_data = ctx.user().map(|u| u.into()); +#[serde_as] +#[derive(Debug, Serialize, Deserialize)] +pub struct SeAttestationClaims { + #[serde_as(as = "Base64")] + cuid: ConfigUid, + #[serde_as(as = "Base64")] + user_data: Vec, + version: u32, + #[serde_as(as = "Base64")] + image_phkh: Vec, + #[serde_as(as = "Base64")] + attestation_phkh: Vec, + #[serde_as(as = "Base64")] + seht: [u8; 16], +} + +#[serde_as] +#[derive(Debug, Serialize, Deserialize)] +pub struct SeAttestationRequest { + #[serde_as(as = "Base64")] + request_blob: Vec, + measurement_size: u32, + additional_size: u32, + #[serde_as(as = "Base64")] + encr_measurement_key: Vec, + #[serde_as(as = "Base64")] + encr_request_nonce: Vec, + #[serde_as(as = "Base64")] + image_hdr_tags: BootHdrTags, +} + +impl SeAttestationRequest { + pub fn from_slice(request: &[u8]) -> Result { + Ok(serde_json::from_slice(request).unwrap()) + } + + pub fn from_str(request: &str) -> Result { + Ok(serde_json::from_str(request).unwrap()) + } + + pub fn create( + hkds: &Vec, + certs: &Vec, + crls: &Vec, + root_ca_path: &Option, + image_hdr_tags: &mut BootHdrTags, + pub_key_file: &str, + ) -> Result { + let att_version = AttestationVersion::One; + let meas_alg = AttestationMeasAlg::HmacSha512; + + let mut att_flags = AttestationFlags::default(); + att_flags.set_image_phkh(); + att_flags.set_attest_phkh(); + let mut arcb = AttestationRequest::new(att_version, meas_alg, att_flags)?; + let verifier = CertVerifier::new(certs.as_slice(), crls.as_slice(), root_ca_path, false)?; + + for hkd in hkds { + let hk = read_file(hkd, "host-key document")?; + let certs = read_certs(&hk)?; + if certs.is_empty() { + warn!("The host key document in '{hkd}' contains empty certificate!"); + } + if certs.len() != 1 { + warn!("The host key document in '{hkd}' contains more than one certificate!") + } + // Panic: len is == 1 -> unwrap will succeed/not panic + let c = certs.first().unwrap(); + verifier.verify(c)?; + arcb.add_hostkey(c.public_key()?); + } + let encr_ctx = ReqEncrCtx::random(SymKeyType::Aes256)?; + let request_blob = arcb.encrypt(&encr_ctx)?; + + let mut file = File::open(pub_key_file)?; + let mut contents = vec![]; + file.read_to_end(&mut contents)?; + let rsa = Rsa::public_key_from_pem(&contents)?; + let rsa_public_key = &PKey::from_rsa(rsa)?; + + let conf_data = arcb.confidential_data(); + let encr_measurement_key = + encrypt_measurement_key(conf_data.measurement_key(), rsa_public_key); + let encr_request_nonce = + encrypt_measurement_key(conf_data.nonce().clone().unwrap().value(), rsa_public_key); Ok(Self { - cuid: ctx.config_uid()?.into(), - additional_data: ctx.additional().map(|a| a.into()), - additional_data_fields, - user_data, + request_blob, + measurement_size: meas_alg.exp_size(), + additional_size: arcb.flags().expected_additional_size(), + encr_measurement_key, + encr_request_nonce, + image_hdr_tags: *image_hdr_tags, }) } } -impl<'a> Display for VerifyOutput<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!(f, "Config UID:")?; - writeln!(f, "{:#}", self.cuid)?; - if let Some(data) = &self.additional_data { - writeln!(f, "Additional-data:")?; - writeln!(f, "{:#}", data)?; - } - if let Some(data) = &self.additional_data_fields { - writeln!(f, "Additional-data content:")?; - writeln!(f, "{:#}", data)?; - } - if let Some(data) = &self.user_data { - writeln!(f, "user-data:")?; - writeln!(f, "{:#}", data)?; - } - Ok(()) - } +#[serde_as] +#[derive(Debug, Serialize, Deserialize)] +pub struct SeAttestationResponse { + #[serde_as(as = "Base64")] + measurement: Vec, + #[serde_as(as = "Base64")] + additional_data: Vec, + #[serde_as(as = "Base64")] + user_data: Vec, + #[serde_as(as = "Base64")] + cuid: ConfigUid, + #[serde_as(as = "Base64")] + encr_measurement_key: Vec, + #[serde_as(as = "Base64")] + encr_request_nonce: Vec, + #[serde_as(as = "Base64")] + image_hdr_tags: BootHdrTags, } -pub fn verify(input: &mut dyn Read, hdr_file: String, arpk_file: String, output: &mut Vec, user_data: &mut Vec) -> Result { - let mut img = open_file(&hdr_file)?; - let arpk = SymKey::Aes256( - read_exact_file(&arpk_file, "Attestation request protection key").map(Confidential::new)?, - ); - let hdr = BootHdrTags::from_se_image(&mut img)?; - let ctx = ExchangeFormatCtx::read(mut input, true)?; - - let (auth, conf) = AttestationRequest::decrypt_bin(ctx.arcb(), &arpk)?; - let meas_key = PKey::hmac(conf.measurement_key())?; - let items = AttestationItems::from_exchange(&ctx, &hdr, conf.nonce())?; - - let measurement = - AttestationMeasurement::calculate(items, AttestationMeasAlg::HmacSha512, &meas_key)?; - - let uv_meas = ctx.measurement().ok_or(anyhow!( - "The input is missing the measurement. It is probably no attestation response" - ))?; - if !measurement.eq_secure(uv_meas) { - debug!("Measurement values:"); - debug!("Recieved: {}", HexSlice::from(uv_meas)); - debug!("Calculated: {}", HexSlice::from(measurement.as_ref())); - warn!("Attestation measurement verification failed. Calculated and received attestation measurement are not equal."); - return Ok(ExitCode::from(EXIT_CODE_ATTESTATION_FAIL)); +impl SeAttestationResponse { + pub fn from_slice(response: &[u8]) -> Result { + Ok(serde_json::from_slice(response).unwrap()) } - warn!("Attestation measurement verified"); - // Error impossible CUID is present Attestation verified - let pr_data = VerifyOutput::from_exchange(&ctx, auth.flags())?; - - warn!("{pr_data}"); - serde_yaml::to_writer(output, &pr_data)?; - - // How to get user_data, what's data here??? - if let Some(user_data) = &user_data { - match ctx.user() { - Some(data) => write_file(user_data, data, "user-data")?, - None => { - warn!("Location for `user-data` specified, but respose does not contain any user-data") - } + + pub fn from_str(request: &str) -> Result { + Ok(serde_json::from_str(request).unwrap()) + } + + pub fn create( + measurement: &[u8], + additional_data: &[u8], + user_data: &[u8], + cuid: &ConfigUid, + encr_measurement_key: &[u8], + encr_request_nonce: &[u8], + image_hdr_tags: &BootHdrTags, + ) -> Result { + Ok(Self { + measurement: measurement.to_vec(), + additional_data: additional_data.to_vec(), + user_data: user_data.to_vec(), + cuid: *cuid, + encr_measurement_key: encr_measurement_key.to_vec(), + encr_request_nonce: encr_request_nonce.to_vec(), + image_hdr_tags: *image_hdr_tags, + }) + } + + pub fn verify(&self, priv_key_file: &str) -> Result { + let mut file = File::open(priv_key_file)?; + let mut contents = vec![]; + file.read_to_end(&mut contents)?; + + let rsa = Rsa::private_key_from_pem(&contents)?; + let rsa_private_key = &PKey::from_rsa(rsa)?; + + let meas_key = decrypt_measurement_key(&self.encr_measurement_key, rsa_private_key); + let nonce = decrypt_measurement_key(&self.encr_request_nonce, rsa_private_key); + + if nonce.len() != 16 { + return Err(anyhow!("The nonce vector must have exactly 16 elements.")); } - }; + let boxed_slice: Box<[u8]> = nonce.into_boxed_slice(); + let boxed_array: Box<[u8; 16]> = match boxed_slice.try_into() { + Ok(ba) => ba, + Err(_) => return Err(anyhow!("Failed to convert nonce from Vec to [u8; 16].")), + }; + let nonce_array: [u8; 16] = *boxed_array; - Ok(ExitCode::SUCCESS) -} + let meas_key = &PKey::hmac(&meas_key)?; + let items = AttestationItems::new( + &self.image_hdr_tags, + &self.cuid, + Some(&self.user_data), + Some(&nonce_array), + Some(&self.additional_data), + ); -pub fn create(host_key_documents: Vec, certs: Vec, crls: Vec, arpk_file: String, root_ca: Option) -> Result> { - let att_version = AttestationVersion::One; - let meas_alg = AttestationMeasAlg::HmacSha512; + let measurement = + AttestationMeasurement::calculate(items, AttestationMeasAlg::HmacSha512, meas_key) + .unwrap(); - let mut att_flags = AttestationFlags::default(); - att_flags.set_image_phkh(); + if !measurement.eq_secure(&self.measurement) { + debug!("Recieved: {:?}", HexSlice::from(&self.measurement)); + debug!("Calculated: {:?}", HexSlice::from(measurement.as_ref())); + warn!("Attestation measurement verification failed. Calculated and received attestation measurement are not equal."); + return Err(anyhow!("Failed to verify the measurement!")); + } + + let userdata = serde_json::from_slice(&self.user_data)?; + debug!("user_data: {:?}", userdata); + // TODO check UserData.image_btph with previous saved value + + let mut att_flags = AttestationFlags::default(); + att_flags.set_image_phkh(); + att_flags.set_attest_phkh(); + let add_data = AdditionalData::from_slice(&self.additional_data, &att_flags)?; + debug!("additional_data: {:?}", add_data); + let image_phkh = add_data + .image_public_host_key_hash() + .ok_or(anyhow!("Failed to get image_public_host_key_hash."))?; + let attestation_phkh = add_data + .attestation_public_host_key_hash() + .ok_or(anyhow!("Failed to get attestation_public_host_key_hash."))?; + + // TODO image_phkh and attestation_phkh with previous saved value + + let claims = SeAttestationClaims { + cuid: self.cuid, + user_data: self.user_data.clone(), + version: AttestationVersion::One as u32, + image_phkh: image_phkh.to_vec(), + attestation_phkh: attestation_phkh.to_vec(), + seht: *self.image_hdr_tags.seht(), + }; + Ok(claims) + } +} + +pub fn create( + hkds: &Vec, + certs: &Vec, + crls: &Vec, + ca: String, + se_img_hdr: &str, + pub_key_file: &str, +) -> Result { + debug!("hkds: {:#?}", hkds); + debug!("certs: {:#?}", certs); + debug!("ca: {:#?}", ca); + debug!("se_img_hdr: {:#?}", se_img_hdr); + debug!("pub_key_file: {:#?}", pub_key_file); - let mut arcb = AttestationRequest::new(att_version, meas_alg, att_flags)?; - debug!("Generated Attestation request"); + let mut hdr_file = open_file(se_img_hdr)?; + let mut image_hdr_tags = BootHdrTags::from_se_image(&mut hdr_file).unwrap(); + let root_ca = &Some(ca); - let certificate_args = CertificateOptions { - host_key_documents, - no_verify: true, + let se_request = SeAttestationRequest::create( + hkds, certs, - crls, - offline: true, + crls, root_ca, - }; - // Add host-key documents - certificate_args - .get_verified_hkds("attestation request")? - .into_iter() - .for_each(|k| arcb.add_hostkey(k)); - debug!("Added all host-keys"); - - let encr_ctx = - ReqEncrCtx::random(SymKeyType::Aes256).context("Failed to generate random input")?; - let ser_arcb = arcb.encrypt(&encr_ctx)?; - warn!("Successfully generated the request"); - - let output: Vec; - let exch_ctx = ExchangeFormatCtx::new_request( - ser_arcb, - meas_alg.exp_size(), - arcb.flags().expected_additional_size().into(), - )?; - exch_ctx.write(&mut output, ExchangeFormatVersion::One)?; - - let arpk = match encr_ctx.prot_key() { - SymKey::Aes256(k) => k, - _ => bail!("Unexpected key type"), - }; - write_file( - &arpk_file, - arpk.value(), - "Attestation request Protection Key", - )?; - - Result::Ok(output) + &mut image_hdr_tags, + pub_key_file, + ) + .unwrap(); + + let challenge = serde_json::to_string(&se_request)?; + debug!("challenge json: {:#?}", challenge); + + Ok(challenge) +} + +pub fn verify(response: &[u8], priv_key_file: &str) -> Result { + // response is serialized SeAttestationResponse String bytes + let response_str = std::str::from_utf8(response)?; + debug!("SeAttestationResponse json: {:#?}", response_str); + let se_response = SeAttestationResponse::from_str(&response_str)?; + + let claims = se_response.verify(priv_key_file)?; + debug!("claims json: {:#?}", claims); + + Ok(claims) } diff --git a/attestation-service/verifier/src/se/mod.rs b/attestation-service/verifier/src/se/mod.rs index b9f99da13b..ca89eb2aa4 100644 --- a/attestation-service/verifier/src/se/mod.rs +++ b/attestation-service/verifier/src/se/mod.rs @@ -4,15 +4,40 @@ // use super::*; -use async_trait::async_trait; -use base64::prelude::*; -use serde_json::json; -use std::io::Cursor; -use pv::misc::CertificateOptions; +use crate::se::ibmse::SeAttestationClaims; use crate::{InitDataHash, ReportData}; +use async_trait::async_trait; +use std::fs; pub mod ibmse; +const SE_HOST_KEY_DOCUMENTS_ROOT: &str = "/run/confidential-containers/ibmse/hkds"; +const SE_CERTIFICATES_ROOT: &str = "/run/confidential-containers/ibmse/certs"; +const SE_CERTIFICATE_ROOT_CA: &str = "/run/confidential-containers/ibmse/certs/ca"; +const SE_CERTIFICATE_REVOCATION_LISTS_ROOT: &str = "/run/confidential-containers/ibmse/crls"; +const SE_IMAGE_HEADER_FILE: &str = "/run/confidential-containers/ibmse/hdr/hdr.bin"; +const SE_MEASUREMENT_ENCR_KEY_PRIVATE: &str = + "/run/confidential-containers/ibmse/rsa/encrypt_key.pem"; +const SE_MEASUREMENT_ENCR_KEY_PUBLIC: &str = + "/run/confidential-containers/ibmse/rsa/encrypt_key.pub"; + +fn list_files_in_folder(dir: &str) -> Result> { + let mut file_paths = Vec::new(); + + for entry in fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + + if path.is_file() { + if let Some(path_str) = path.to_str() { + file_paths.push(path_str.to_string()); + } + } + } + + Ok(file_paths) +} + #[derive(Debug, Default)] pub struct SeVerifier {} @@ -31,15 +56,22 @@ impl Verifier for SeVerifier { &self, _tee_parameters: String, ) -> Result { - let hkds: Vec = vec![String::new(); 2]; - let certs: Vec = vec![String::new(); 2]; - let crls: Vec = vec![]; - let arpk = String::from("arpk_file_path"); - let root_ca = Option::Some(String::from("root_ca")); - - let challenge = ibmse::create(hkds, certs, crls, arpk, root_ca)?; + let hkds = list_files_in_folder(SE_HOST_KEY_DOCUMENTS_ROOT)?; + let certs = list_files_in_folder(SE_CERTIFICATES_ROOT)?; + let crls = list_files_in_folder(SE_CERTIFICATE_REVOCATION_LISTS_ROOT)?; + let ca = String::from(SE_CERTIFICATE_ROOT_CA); + // challenge is Serialized SeAttestationRequest, attester uses it to do perform action + // attester then generates and return Serialized SeAttestationResponse + let challenge = ibmse::create( + &hkds, + &certs, + &crls, + ca, + SE_IMAGE_HEADER_FILE, + SE_MEASUREMENT_ENCR_KEY_PUBLIC, + ); - Ok(BASE64_STANDARD.encode(challenge)) + challenge } } @@ -48,19 +80,12 @@ async fn verify_evidence( _expected_report_data: &ReportData<'_>, _expected_init_data_hash: &InitDataHash<'_>, ) -> Result { - let arpk = String::from("arpk_file_path"); - let hdr = String::from("hdr_file_path"); - - let mut cursor = Cursor::new(evidence); - let mut output: Vec = vec![]; - let mut userdata: Vec = vec![]; - let _res = ibmse::verify(&mut cursor, hdr, arpk, &mut output, &mut userdata); - - let claims_map = json!({ - "serial_number": format!("{}", "SE-ID"), - "measurement": format!("{}", BASE64_STANDARD.encode(output.clone())), - "report_data": format!("{}", BASE64_STANDARD.encode(userdata.clone())), - }); + // evidence is serialized SeAttestationResponse String bytes + let mut se_claims = ibmse::verify(evidence, SE_MEASUREMENT_ENCR_KEY_PRIVATE)?; + se_generate_parsed_claim(&mut se_claims).map_err(|e| anyhow!("error from se Verifier: {:?}", e)) +} - Ok(claims_map as TeeEvidenceParsedClaim) +fn se_generate_parsed_claim(se_claims: &mut SeAttestationClaims) -> Result { + let v = serde_json::to_value(se_claims).context("build json value from the se claims")?; + Ok(v as TeeEvidenceParsedClaim) }