diff --git a/backport-init-attestation.patch b/backport-init-attestation.patch new file mode 100644 index 0000000000000000000000000000000000000000..0301e609a099e12dfa65589c4eba2870bcd1afc7 --- /dev/null +++ b/backport-init-attestation.patch @@ -0,0 +1,1665 @@ +From d06b6beab9ae13898870297e8ef2ae806cd8d6d0 Mon Sep 17 00:00:00 2001 +From: houmingyong +Date: Tue, 28 May 2024 10:25:41 +0800 +Subject: [PATCH] init attestation + +The current patch incorporates the following four commit points: + +Reference: https://gitee.com/openeuler/secGear/commit/d06b6beab9ae13898870297e8ef2ae806cd8d6d0 + https://gitee.com/openeuler/secGear/commit/b90e039631f1031a485ef038174c0bef831223a5 + https://gitee.com/openeuler/secGear/commit/dad056809c5e94b50c47063d728d5f1e47800512 + https://gitee.com/openeuler/secGear/commit/ce4c7b6a8c013cd208004a3cec13a15fff100b1a +Conflict:no +--- + .../attestation/attestation-agent/Cargo.toml | 30 ++ + .../attestation/attestation-agent/README.md | 5 + + .../attestation-agent/agent/Cargo.toml | 38 ++ + .../agent/attestation-agent.example.toml | 1 + + .../attestation-agent/agent/src/agent.rs | 144 +++++++ + .../agent/src/bin/aa-test/main.rs | 68 ++++ + .../agent/src/bin/generate-headers/main.rs | 4 + + .../attestation-agent/agent/src/lib.rs | 53 +++ + .../attestation-agent/attester/Cargo.toml | 24 ++ + .../attester/src/itrustee/itrustee.rs | 51 +++ + .../attester/src/itrustee/mod.rs | 130 ++++++ + .../attestation-agent/attester/src/lib.rs | 90 +++++ + .../attester/src/virtcca/mod.rs | 88 +++++ + .../attester/src/virtcca/virtcca.rs | 108 +++++ + .../rust_attestation_agent.h | 56 +++ + .../attestation-service/Cargo.toml | 22 ++ + .../attestation-service/verifier/Cargo.toml | 27 ++ + .../verifier/src/itrustee/itrustee.rs | 53 +++ + .../verifier/src/itrustee/mod.rs | 58 +++ + .../attestation-service/verifier/src/lib.rs | 51 +++ + .../verifier/src/virtcca/mod.rs | 373 ++++++++++++++++++ + 21 files changed, 1474 insertions(+) + create mode 100644 service/attestation/attestation-agent/Cargo.toml + create mode 100644 service/attestation/attestation-agent/README.md + create mode 100644 service/attestation/attestation-agent/agent/Cargo.toml + create mode 100644 service/attestation/attestation-agent/agent/attestation-agent.example.toml + create mode 100644 service/attestation/attestation-agent/agent/src/agent.rs + create mode 100644 service/attestation/attestation-agent/agent/src/bin/aa-test/main.rs + create mode 100644 service/attestation/attestation-agent/agent/src/bin/generate-headers/main.rs + create mode 100644 service/attestation/attestation-agent/agent/src/lib.rs + create mode 100644 service/attestation/attestation-agent/attester/Cargo.toml + create mode 100644 service/attestation/attestation-agent/attester/src/itrustee/itrustee.rs + create mode 100644 service/attestation/attestation-agent/attester/src/itrustee/mod.rs + create mode 100644 service/attestation/attestation-agent/attester/src/lib.rs + create mode 100644 service/attestation/attestation-agent/attester/src/virtcca/mod.rs + create mode 100644 service/attestation/attestation-agent/attester/src/virtcca/virtcca.rs + create mode 100644 service/attestation/attestation-agent/rust_attestation_agent.h + create mode 100644 service/attestation/attestation-service/Cargo.toml + create mode 100644 service/attestation/attestation-service/verifier/Cargo.toml + create mode 100644 service/attestation/attestation-service/verifier/src/itrustee/itrustee.rs + create mode 100644 service/attestation/attestation-service/verifier/src/itrustee/mod.rs + create mode 100644 service/attestation/attestation-service/verifier/src/lib.rs + create mode 100644 service/attestation/attestation-service/verifier/src/virtcca/mod.rs + +diff --git a/service/attestation/attestation-agent/Cargo.toml b/service/attestation/attestation-agent/Cargo.toml +new file mode 100644 +index 0000000..7a424e6 +--- /dev/null ++++ b/service/attestation/attestation-agent/Cargo.toml +@@ -0,0 +1,30 @@ ++[workspace] ++resolver = "2" ++members = [ ++ "agent", ++ "attester", ++] ++ ++[workspace.dependencies] ++serde = "=1.0.203" ++half = "=1.6" ++ciborium-ll = "=0.2.0" ++ciborium-io = "=0.2.0" ++ciborium = "=0.2.0" ++anyhow = "1.0" ++serde_json = "1.0" ++async-trait = "=0.1.78" ++cose-rust = "=0.1.7" ++hex = "0.4" ++openssl = "=0.10.64" ++log = "=0.4.14" ++ ++config = "=0.13.0" ++rand = "=0.8.5" ++base64-url = "=3.0.0" ++tokio = "1.0" ++env_logger = "=0.4.0" ++safer-ffi = "=0.1.8" ++futures = "=0.3.30" ++ ++verifier = {path = "../attestation-service/verifier", default-features = false} +diff --git a/service/attestation/attestation-agent/README.md b/service/attestation/attestation-agent/README.md +new file mode 100644 +index 0000000..0157e59 +--- /dev/null ++++ b/service/attestation/attestation-agent/README.md +@@ -0,0 +1,5 @@ ++# Attestation Agent ++The Attestation Agent is deployed on the TEE node, provide get_evidence, get_token, verify_evidece interface, etc. ++ ++# Overview ++TODO +diff --git a/service/attestation/attestation-agent/agent/Cargo.toml b/service/attestation/attestation-agent/agent/Cargo.toml +new file mode 100644 +index 0000000..66919d9 +--- /dev/null ++++ b/service/attestation/attestation-agent/agent/Cargo.toml +@@ -0,0 +1,38 @@ ++[package] ++name = "attestation-agent" ++version = "0.1.0" ++edition = "2021" ++ ++[[bin]] ++name = "aa-test" ++ ++[[bin]] ++name = "generate-headers" ++required-features = ["headers"] ++ ++[lib] ++name = "attestation_agent" ++crate-type = ["lib", "cdylib"] ++ ++[features] ++no_as = [ "verifier" ] ++all = ["itrustee", "virtcca"] ++itrustee = ["attester/itrustee-attester", "verifier/itrustee-verifier"] ++virtcca = ["attester/virtcca-attester", "verifier/virtcca-verifier"] ++headers = ["safer-ffi/headers"] ++ ++[dependencies] ++anyhow.workspace = true ++config.workspace = true ++serde.workspace = true ++serde_json.workspace = true ++rand.workspace = true ++async-trait.workspace = true ++tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } ++log.workspace = true ++env_logger.workspace = true ++safer-ffi.workspace = true ++futures.workspace = true ++ ++attester = { path = "../attester" } ++verifier = { workspace = true, optional = true } +diff --git a/service/attestation/attestation-agent/agent/attestation-agent.example.toml b/service/attestation/attestation-agent/agent/attestation-agent.example.toml +new file mode 100644 +index 0000000..4ba5ef2 +--- /dev/null ++++ b/service/attestation/attestation-agent/agent/attestation-agent.example.toml +@@ -0,0 +1 @@ ++svr_url = "http://127.0.0.1:8888" +diff --git a/service/attestation/attestation-agent/agent/src/agent.rs b/service/attestation/attestation-agent/agent/src/agent.rs +new file mode 100644 +index 0000000..9aec2bb +--- /dev/null ++++ b/service/attestation/attestation-agent/agent/src/agent.rs +@@ -0,0 +1,144 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++//! Attestation Agent ++//! ++//! This crate provides some APIs to get and verify the TEE evidence. ++//! Current supports kunpeng itrustee and virtcca TEE types. ++ ++use anyhow::Result; ++use log; ++use serde::{Serialize, Deserialize}; ++use async_trait::async_trait; ++ ++use attester::{Attester, AttesterAPIs}; ++ ++#[cfg(feature = "no_as")] ++use verifier::{Verifier, VerifierAPIs}; ++ ++const DEFAULT_AA_CONF_PATH: &str = "/etc/attestation/attestation-agent.toml"; ++ ++pub use attester::EvidenceRequest; ++ ++#[async_trait] ++pub trait AttestationAgentAPIs { ++ /// `get_evidence`: get hardware TEE signed evidence due to given user_data, ++ /// such as input random challenge to prevent replay attacks ++ async fn get_evidence(&self, user_data: EvidenceRequest) -> Result>; ++ ++ /// `verify_evidence`: verify the integrity of TEE evidence and evaluate the ++ /// claims against the supplied reference values ++ async fn verify_evidence(&self, challenge: &[u8], evidence: &[u8]) -> Result<()>; ++} ++ ++#[async_trait] ++impl AttestationAgentAPIs for AttestationAgent { ++ async fn get_evidence(&self, user_data: EvidenceRequest) -> Result> { ++ Attester::default().tee_get_evidence(user_data).await ++ } ++ async fn verify_evidence(&self, challenge: &[u8], evidence: &[u8]) -> Result<()> { ++ #[cfg(feature = "no_as")] ++ let _ret = Verifier::default().verify_evidence(challenge, evidence).await?; ++ ++ let _ret = request_as(challenge, evidence); ++ return _ret; ++ } ++} ++ ++fn request_as(challenge: &[u8], evidence: &[u8]) -> Result<()> { ++ let _ = challenge; ++ let _ = evidence; ++ // todo send request to attestation service ++ Ok(()) ++} ++ ++#[derive(Clone, Debug, Serialize, Deserialize)] ++struct AAConfig { ++ svr_url: String, // Attestation Service url ++} ++ ++impl Default for AAConfig { ++ fn default() -> Self { ++ Self { ++ svr_url: String::from(""), ++ } ++ } ++} ++ ++impl TryFrom<&str> for AAConfig { ++ type Error = config::ConfigError; ++ fn try_from(config_path: &str) -> Result { ++ let c = config::Config::builder() ++ .add_source(config::File::with_name(config_path)) ++ .build()?; ++ let cfg = c.try_deserialize()?; ++ Ok(cfg) ++ } ++} ++ ++#[derive(Debug)] ++pub struct AttestationAgent { ++ _config: AAConfig, ++} ++ ++impl Default for AttestationAgent { ++ fn default() -> Self { ++ if let Ok(_config) = AAConfig::try_from(DEFAULT_AA_CONF_PATH) { ++ log::info!("attestation agent construct with default config file"); ++ return AttestationAgent { _config }; ++ } ++ log::warn!("The default conf file {} is missing", DEFAULT_AA_CONF_PATH); ++ Self { ++ _config: AAConfig::default(), ++ } ++ } ++} ++ ++#[allow(dead_code)] ++impl AttestationAgent { ++ pub fn new(conf_path: Option<&str>) -> Result { ++ let _config = match conf_path { ++ Some(conf_path) => { ++ log::info!("Attestation Agent config file:{conf_path}"); ++ AAConfig::try_from(conf_path)? ++ } ++ None => { ++ log::warn!("No Attestation Agent config file specified. Using a default config"); ++ AAConfig::default() ++ } ++ }; ++ Ok(AttestationAgent {_config}) ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ use crate::agent::*; ++ ++ #[test] ++ fn aa_default_conf_file() { ++ let aa = AttestationAgent::default(); ++ assert_eq!(aa._config.svr_url, "http://127.0.0.1:8000"); ++ } ++ ++ #[test] ++ fn aa_new_no_conf_path() { ++ let aa = AttestationAgent::new(None).unwrap(); ++ assert_eq!(aa._config.svr_url, ""); ++ } ++ ++ #[test] ++ fn aa_new_with_example_conf() { ++ let aa = AttestationAgent::new(Some("attestation-agent.example.toml")).unwrap(); ++ assert_eq!(aa._config.svr_url, "http://127.0.0.1:8888"); ++ } ++} +diff --git a/service/attestation/attestation-agent/agent/src/bin/aa-test/main.rs b/service/attestation/attestation-agent/agent/src/bin/aa-test/main.rs +new file mode 100644 +index 0000000..5cedfc8 +--- /dev/null ++++ b/service/attestation/attestation-agent/agent/src/bin/aa-test/main.rs +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++//! This is a test bin, test get evidence and verify ++//! on kunpeng platform, libqca has white ta lists, need copy target/debug/attestation-agent to /vendor/bin/ ++ ++use rand::{self, RngCore}; ++use tokio; ++use env_logger; ++ ++const TEST_THREAD_NUM: i64 = 1; // multi thread num ++ ++//mod agent; ++use attestation_agent::agent::*; ++ ++#[tokio::main] ++async fn main() { ++ env_logger::init(); ++ let mut handles = Vec::with_capacity(TEST_THREAD_NUM as usize); ++ for i in 0..TEST_THREAD_NUM { ++ let t = tokio::spawn(async move {attestation_proc(i).await;}); ++ handles.push(t); ++ } ++ ++ for handle in handles { ++ let _ = tokio::join!(handle); ++ } ++ println!("main stop"); ++} ++ ++async fn attestation_proc(i: i64) { ++ println!("attestation_proc {} start", i); ++ let aa: AttestationAgent = AttestationAgent::default(); ++ ++ let mut nonce: [u8; 16] = [0; 16]; ++ rand::thread_rng().fill_bytes(&mut nonce); ++ ++ // Step1: construct input param ++ let user_data: attester::EvidenceRequest = attester::EvidenceRequest { ++ uuid: String::from("f68fd704-6eb1-4d14-b218-722850eb3ef0"), ++ challenge: nonce.to_vec(), ++ }; ++ ++ // Step2: get tee evidence ++ let evidence = aa.get_evidence(user_data).await; ++ match evidence { ++ Ok(evidence) => { ++ println!("get evidence success"); ++ // Step3: verify evidence ++ let ret = aa.verify_evidence(&nonce, &evidence).await; ++ match ret { ++ Ok(_) => println!("verify evidence success"), ++ Err(_) =>println!("verify evidence failed"), ++ } ++ }, ++ Err(e) => println!("get evidence failed: {}", e), ++ } ++ println!("attestation_proc {} end", i); ++} +\ No newline at end of file +diff --git a/service/attestation/attestation-agent/agent/src/bin/generate-headers/main.rs b/service/attestation/attestation-agent/agent/src/bin/generate-headers/main.rs +new file mode 100644 +index 0000000..3eb4334 +--- /dev/null ++++ b/service/attestation/attestation-agent/agent/src/bin/generate-headers/main.rs +@@ -0,0 +1,4 @@ ++use attestation_agent; ++fn main() -> ::std::io::Result<()> { ++ attestation_agent::generate_headers() ++} +\ No newline at end of file +diff --git a/service/attestation/attestation-agent/agent/src/lib.rs b/service/attestation/attestation-agent/agent/src/lib.rs +new file mode 100644 +index 0000000..0f1efc2 +--- /dev/null ++++ b/service/attestation/attestation-agent/agent/src/lib.rs +@@ -0,0 +1,53 @@ ++use agent::*; ++pub mod agent; ++ ++// c interface ++use safer_ffi::prelude::*; ++use futures::executor::block_on; ++use attester::EvidenceRequest; ++ ++#[ffi_export] ++pub fn get_reprot(c_uuid: &repr_c::String, c_challenge: &repr_c::Vec) -> repr_c::Vec { ++ let input = EvidenceRequest { ++ uuid: c_uuid.clone().to_string(), ++ challenge: c_challenge.clone().to_vec(), ++ }; ++ ++ let fut = async { ++ agent::AttestationAgent::default().get_evidence(input).await ++ }; ++ let report: Vec = match block_on(fut) { ++ Ok(report) => report, ++ Err(e) => { ++ println!("get report failed {:?}", e); ++ Vec::new() ++ }, ++ }; ++ ++ report.into() ++} ++ ++#[ffi_export] ++pub fn verify_report(c_challenge: &repr_c::Vec, report: &repr_c::Vec) -> safer_ffi::libc::c_int { ++ let fut = async {agent::AttestationAgent::default().verify_evidence( ++ &c_challenge.clone().to_vec(), &report.clone().to_vec()).await}; ++ let ret = block_on(fut); ++ if ret.is_err() { ++ println!("verfiy report failed"); ++ return 1; ++ } ++ return 0; ++} ++ ++#[ffi_export] ++pub fn free_report(report: repr_c::Vec) { ++ drop(report); ++} ++ ++// The following function is only necessary for the header generation. ++#[cfg(feature = "headers")] ++pub fn generate_headers() -> ::std::io::Result<()> { ++ ::safer_ffi::headers::builder() ++ .to_file("rust_attestation_agent.h")? ++ .generate() ++} +\ No newline at end of file +diff --git a/service/attestation/attestation-agent/attester/Cargo.toml b/service/attestation/attestation-agent/attester/Cargo.toml +new file mode 100644 +index 0000000..575e63f +--- /dev/null ++++ b/service/attestation/attestation-agent/attester/Cargo.toml +@@ -0,0 +1,24 @@ ++[package] ++name = "attester" ++version = "0.1.0" ++edition = "2021" ++ ++[features] ++itrustee-attester = [ "base64-url", "rand" ] ++virtcca-attester = [] ++ ++[dependencies] ++anyhow.workspace = true ++serde.workspace = true ++serde_json.workspace = true ++rand = { workspace = true, optional = true } ++base64-url = { workspace = true, optional = true } ++async-trait.workspace = true ++log.workspace = true ++ ++[dev-dependencies] ++ ++ ++ ++ ++ +diff --git a/service/attestation/attestation-agent/attester/src/itrustee/itrustee.rs b/service/attestation/attestation-agent/attester/src/itrustee/itrustee.rs +new file mode 100644 +index 0000000..9a711c2 +--- /dev/null ++++ b/service/attestation/attestation-agent/attester/src/itrustee/itrustee.rs +@@ -0,0 +1,51 @@ ++/* automatically generated by rust-bindgen 0.69.4 */ ++ ++#[repr(C)] ++#[derive(Debug, Copy, Clone)] ++pub struct ra_buffer_data { ++ pub size: ::std::os::raw::c_uint, ++ pub buf: *mut ::std::os::raw::c_uchar, ++} ++#[test] ++fn bindgen_test_layout_ra_buffer_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(ra_buffer_data)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(ra_buffer_data)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(ra_buffer_data), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).buf) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(ra_buffer_data), ++ "::", ++ stringify!(buf) ++ ) ++ ); ++} ++ ++#[link(name = "qca")] ++extern "C" { ++ pub fn RemoteAttest( ++ in_: *mut ra_buffer_data, ++ out: *mut ra_buffer_data, ++ ) -> ::std::os::raw::c_uint; ++} +diff --git a/service/attestation/attestation-agent/attester/src/itrustee/mod.rs b/service/attestation/attestation-agent/attester/src/itrustee/mod.rs +new file mode 100644 +index 0000000..3fde5f7 +--- /dev/null ++++ b/service/attestation/attestation-agent/attester/src/itrustee/mod.rs +@@ -0,0 +1,130 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++//! itrustee tee plugin ++//! ++//! Call the hardware sdk or driver to get the specific evidence ++ ++use anyhow::*; ++use serde_json; ++use std::path::Path; ++use serde::{Serialize, Deserialize}; ++use base64_url; ++use log; ++ ++use crate::EvidenceRequest; ++ ++mod itrustee; ++ ++#[derive(Debug, Default)] ++pub struct ItrusteeAttester {} ++ ++impl ItrusteeAttester { ++ pub async fn tee_get_evidence(&self, user_data: EvidenceRequest) -> Result { ++ let ret = itrustee_provision(); ++ if ret.is_err() { ++ log::error!("itrustee attester provision failed"); ++ bail!("itrustee attester provision failed"); ++ } ++ ++ itrustee_get_evidence(user_data) ++ } ++} ++ ++pub fn detect_platform() -> bool { ++ Path::new("/usr/bin/tee").exists() ++} ++ ++#[derive(Serialize, Deserialize)] ++struct ReportInputPayload { ++ version: String, ++ nonce: String, ++ uuid: String, ++ hash_alg: String, ++ with_tcb: bool, ++ request_key: bool, ++} ++ ++#[derive(Serialize, Deserialize)] ++struct ItrusteeInput { ++ handler: String, ++ payload: ReportInputPayload, ++} ++ ++fn itrustee_get_evidence(user_data: EvidenceRequest) -> Result { ++ let payload = ReportInputPayload { ++ nonce: base64_url::encode(&user_data.challenge), ++ uuid: user_data.uuid, ++ with_tcb: false, ++ request_key: true, ++ version: String::from("TEE.RA.1.0"), ++ hash_alg: String::from("HS256"), ++ }; ++ ++ let itrustee_input: ItrusteeInput = ItrusteeInput { ++ handler: String::from("report-input"), ++ payload: payload, ++ }; ++ let mut buf = serde_json::to_string(&itrustee_input)?; ++ let mut input = itrustee::ra_buffer_data { ++ size: buf.len() as ::std::os::raw::c_uint, ++ buf: buf.as_mut_ptr() as *mut ::std::os::raw::c_uchar, ++ }; ++ ++ let mut report = Vec::new(); ++ report.resize(0x3000, b'\0'); ++ let mut output = itrustee::ra_buffer_data { ++ size: report.len() as ::std::os::raw::c_uint, ++ buf: report.as_mut_ptr() as *mut ::std::os::raw::c_uchar, ++ }; ++ ++ unsafe { ++ let ret = itrustee::RemoteAttest(&mut input, &mut output); ++ if ret != 0 { ++ log::error!("itrustee get report failed, ret:{}", ret); ++ bail!("itrustee get report failed, ret:{}", ret); ++ } ++ let out_len: usize = output.size.try_into()?; ++ report.set_len(out_len); ++ } ++ let str_report = String::from_utf8(report)?; ++ ++ Ok(str_report) ++} ++ ++fn itrustee_provision() -> Result<()> { ++ let json = r#"{"handler":"provisioning-input","payload":{"version":"TEE.RA.1.0","scenario":"sce_no_as","hash_alg":"HS256"}}"#; ++ ++ let provision_input: serde_json::Value = serde_json::from_str(json)?; ++ let mut provision_input = provision_input.to_string(); ++ ++ let mut input = itrustee::ra_buffer_data { ++ size: provision_input.len() as ::std::os::raw::c_uint, ++ buf: provision_input.as_mut_ptr() as *mut ::std::os::raw::c_uchar, ++ }; ++ ++ let mut report = Vec::new(); ++ report.resize(0x3000, b'\0'); ++ ++ let mut output = itrustee::ra_buffer_data { ++ size: report.len() as ::std::os::raw::c_uint, ++ buf: report.as_mut_ptr() as *mut ::std::os::raw::c_uchar, ++ }; ++ unsafe { ++ let ret = itrustee::RemoteAttest(&mut input, &mut output); ++ if ret != 0 { ++ log::error!("itrustee provision failed, ret:{}", ret); ++ bail!("itrustee provision failed, ret:{}", ret); ++ } ++ } ++ Ok(()) ++} +diff --git a/service/attestation/attestation-agent/attester/src/lib.rs b/service/attestation/attestation-agent/attester/src/lib.rs +new file mode 100644 +index 0000000..28bf33c +--- /dev/null ++++ b/service/attestation/attestation-agent/attester/src/lib.rs +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++//! attester ++//! ++//! This crate provides unified APIs to get TEE evidence. ++ ++use anyhow::*; ++use serde::{Serialize, Deserialize}; ++use async_trait::async_trait; ++use log; ++ ++#[cfg(feature = "itrustee-attester")] ++mod itrustee; ++ ++#[cfg(feature = "virtcca-attester")] ++pub mod virtcca; ++ ++#[derive(Debug)] ++pub struct EvidenceRequest { ++ pub uuid: String, ++ pub challenge: Vec, ++} ++ ++#[derive(Debug, Serialize, Deserialize)] ++pub struct Evidence { ++ pub tee: TeeType, ++ pub evidence: String, ++} ++ ++#[async_trait] ++pub trait AttesterAPIs { ++ /// Call tee plugin to get the hardware evidence. ++ /// Automatically detect the TEE type of the current running environment. ++ async fn tee_get_evidence(&self, user_data: EvidenceRequest) -> Result>; ++} ++ ++#[derive(Default)] ++pub struct Attester {} ++ ++#[derive(Debug, Serialize, Deserialize)] ++pub enum TeeType { ++ Itrustee = 1, ++ Virtcca, ++ Invalid, ++} ++ ++const MAX_CHALLENGE_LEN: usize = 64; ++ ++#[async_trait] ++impl AttesterAPIs for Attester { ++ async fn tee_get_evidence(&self, _user_data: EvidenceRequest) -> Result> { ++ let len = _user_data.challenge.len(); ++ if len <= 0 || len > MAX_CHALLENGE_LEN { ++ log::error!("challenge len is error, expecting 0 < len < {}, got {}", MAX_CHALLENGE_LEN, len); ++ bail!("challenge len is error, expecting 0 < len < {}, got {}", MAX_CHALLENGE_LEN, len); ++ } ++ #[cfg(feature = "itrustee-attester")] ++ if itrustee::detect_platform() { ++ let evidence = itrustee::ItrusteeAttester::default().tee_get_evidence(_user_data).await?; ++ let aa_evidence = Evidence { ++ tee: TeeType::Itrustee, ++ evidence: evidence, ++ }; ++ let evidence = serde_json::to_vec(&aa_evidence)?; ++ ++ return Ok(evidence); ++ } ++ #[cfg(feature = "virtcca-attester")] ++ if virtcca::detect_platform() { ++ let evidence = virtcca::VirtccaAttester::default().tee_get_evidence(_user_data).await?; ++ let aa_evidence = Evidence { ++ tee: TeeType::Virtcca, ++ evidence: evidence, ++ }; ++ let evidence = serde_json::to_vec(&aa_evidence)?; ++ return Ok(evidence); ++ } ++ bail!("unkown tee platform"); ++ } ++} +\ No newline at end of file +diff --git a/service/attestation/attestation-agent/attester/src/virtcca/mod.rs b/service/attestation/attestation-agent/attester/src/virtcca/mod.rs +new file mode 100644 +index 0000000..dfb3aef +--- /dev/null ++++ b/service/attestation/attestation-agent/attester/src/virtcca/mod.rs +@@ -0,0 +1,88 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++//! virtcca tee plugin ++//! ++//! Call the hardware sdk or driver to get the specific evidence ++ ++use anyhow::{Result, bail}; ++use std::path::Path; ++use serde::{Serialize, Deserialize}; ++use log; ++ ++use crate::EvidenceRequest; ++use crate::virtcca::virtcca::tsi_free_ctx; ++use self::virtcca::{tsi_new_ctx, get_attestation_token, get_dev_cert}; ++ ++mod virtcca; ++ ++#[derive(Debug, Default)] ++pub struct VirtccaAttester {} ++ ++ ++impl VirtccaAttester { ++ pub async fn tee_get_evidence(&self, user_data: EvidenceRequest) -> Result { ++ let evidence = virtcca_get_token(&user_data.challenge)?; ++ let evidence = serde_json::to_string(&evidence)?; ++ Ok(evidence) ++ } ++} ++ ++pub fn detect_platform() -> bool { ++ Path::new("/dev/tsi").exists() ++} ++ ++#[derive(Debug, Serialize, Deserialize)] ++pub struct VirtccaEvidence { ++ pub evidence: Vec, ++ pub dev_cert: Vec, ++} ++ ++fn virtcca_get_token(challenge: &[u8]) -> Result { ++ unsafe { ++ let ctx = tsi_new_ctx(); ++ ++ let mut challenge = challenge.to_vec(); ++ let p_challenge = challenge.as_mut_ptr() as *mut ::std::os::raw::c_uchar; ++ let challenge_len = challenge.len() as usize; ++ let mut token = Vec::new(); ++ token.resize(4096, b'\0'); ++ let p_token = token.as_mut_ptr() as *mut ::std::os::raw::c_uchar; ++ let mut token_len = token.len(); ++ let p_token_len = &mut token_len as *mut usize; ++ let ret = get_attestation_token(ctx, p_challenge, challenge_len, p_token, p_token_len); ++ if ret != 0 { ++ log::error!("virtcca get attestation token failed {}", ret); ++ bail!("virtcca get attestation token failed {}", ret); ++ } ++ token.set_len(token_len); ++ ++ let mut dev_cert = Vec::new(); ++ dev_cert.resize(4096, b'\0'); ++ let p_dev_cert = dev_cert.as_mut_ptr() as *mut ::std::os::raw::c_uchar; ++ let mut dev_cert_len = dev_cert.len(); ++ let p_dev_cert_len = &mut dev_cert_len as *mut usize; ++ let ret = get_dev_cert(ctx, p_dev_cert, p_dev_cert_len); ++ if ret != 0 { ++ log::error!("get dev cert failed {}", ret); ++ bail!("get dev cert failed {}", ret); ++ } ++ dev_cert.set_len(dev_cert_len); ++ ++ let evidence = VirtccaEvidence { ++ evidence: token, ++ dev_cert: dev_cert, ++ }; ++ let _ = tsi_free_ctx(ctx); ++ Ok(evidence) ++ } ++} +\ No newline at end of file +diff --git a/service/attestation/attestation-agent/attester/src/virtcca/virtcca.rs b/service/attestation/attestation-agent/attester/src/virtcca/virtcca.rs +new file mode 100644 +index 0000000..65da1d8 +--- /dev/null ++++ b/service/attestation/attestation-agent/attester/src/virtcca/virtcca.rs +@@ -0,0 +1,108 @@ ++/* automatically generated by rust-bindgen 0.69.4 */ ++#[allow(non_camel_case_types)] ++pub type wchar_t = ::std::os::raw::c_int; ++#[repr(C)] ++#[repr(align(16))] ++#[derive(Debug, Copy, Clone)] ++pub struct max_align_t { ++ pub __clang_max_align_nonce1: ::std::os::raw::c_longlong, ++ pub __bindgen_padding_0: u64, ++ pub __clang_max_align_nonce2: u128, ++} ++#[test] ++fn bindgen_test_layout_max_align_t() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 32usize, ++ concat!("Size of: ", stringify!(max_align_t)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 16usize, ++ concat!("Alignment of ", stringify!(max_align_t)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).__clang_max_align_nonce1) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(max_align_t), ++ "::", ++ stringify!(__clang_max_align_nonce1) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).__clang_max_align_nonce2) as usize - ptr as usize }, ++ 16usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(max_align_t), ++ "::", ++ stringify!(__clang_max_align_nonce2) ++ ) ++ ); ++} ++#[repr(C)] ++#[derive(Debug, Copy, Clone)] ++pub struct tsi_ctx { ++ pub fd: wchar_t, ++} ++#[test] ++fn bindgen_test_layout_tsi_ctx() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 4usize, ++ concat!("Size of: ", stringify!(tsi_ctx)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 4usize, ++ concat!("Alignment of ", stringify!(tsi_ctx)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).fd) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(tsi_ctx), ++ "::", ++ stringify!(fd) ++ ) ++ ); ++} ++ ++#[link(name = "vccaattestation")] ++extern "C" { ++ pub fn tsi_new_ctx() -> *mut tsi_ctx; ++} ++extern "C" { ++ pub fn tsi_free_ctx(ctx: *mut tsi_ctx); ++} ++extern "C" { ++ #[allow(dead_code)] ++ pub fn get_version( ++ ctx: *mut tsi_ctx, ++ major: *mut wchar_t, ++ minor: *mut wchar_t, ++ ) -> wchar_t; ++} ++extern "C" { ++ pub fn get_attestation_token( ++ ctx: *mut tsi_ctx, ++ challenge: *mut ::std::os::raw::c_uchar, ++ challenge_len: usize, ++ token: *mut ::std::os::raw::c_uchar, ++ token_len: *mut usize, ++ ) -> wchar_t; ++} ++extern "C" { ++ pub fn get_dev_cert( ++ ctx: *mut tsi_ctx, ++ dev_cert: *mut ::std::os::raw::c_uchar, ++ dev_cert_len: *mut usize, ++ ) -> wchar_t; ++} +diff --git a/service/attestation/attestation-agent/rust_attestation_agent.h b/service/attestation/attestation-agent/rust_attestation_agent.h +new file mode 100644 +index 0000000..e06e61e +--- /dev/null ++++ b/service/attestation/attestation-agent/rust_attestation_agent.h +@@ -0,0 +1,56 @@ ++/*! \file */ ++/******************************************* ++ * * ++ * File auto-generated by `::safer_ffi`. * ++ * * ++ * Do not manually edit this file. * ++ * * ++ *******************************************/ ++ ++#ifndef __RUST_ATTESTATION_AGENT__ ++#define __RUST_ATTESTATION_AGENT__ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++ ++#include ++#include ++ ++/** \brief ++ * Same as [`Vec`][`rust::Vec`], but with guaranteed `#[repr(C)]` layout ++ */ ++typedef struct Vec_uint8 { ++ /** */ ++ uint8_t * ptr; ++ ++ /** */ ++ size_t len; ++ ++ /** */ ++ size_t cap; ++} Vec_uint8_t; ++ ++/** */ ++void ++free_report ( ++ Vec_uint8_t report); ++ ++/** */ ++Vec_uint8_t ++get_reprot ( ++ Vec_uint8_t const * c_uuid, ++ Vec_uint8_t const * c_challenge); ++ ++/** */ ++int32_t ++verify_report ( ++ Vec_uint8_t const * c_challenge, ++ Vec_uint8_t const * report); ++ ++ ++#ifdef __cplusplus ++} /* extern \"C\" */ ++#endif ++ ++#endif /* __RUST_ATTESTATION_AGENT__ */ +diff --git a/service/attestation/attestation-service/Cargo.toml b/service/attestation/attestation-service/Cargo.toml +new file mode 100644 +index 0000000..e244637 +--- /dev/null ++++ b/service/attestation/attestation-service/Cargo.toml +@@ -0,0 +1,22 @@ ++[workspace] ++resolver = "2" ++members = [ ++ #"service", ++ "verifier", ++] ++ ++[workspace.dependencies] ++serde = "=1.0.203" ++half = "=1.6" ++ciborium-ll = "=0.2.0" ++ciborium-io = "=0.2.0" ++ciborium = "=0.2.0" ++anyhow = "1.0" ++serde_json = "1.0" ++async-trait = "=0.1.78" ++cose-rust = "=0.1.7" ++hex = "0.4" ++openssl = "=0.10.64" ++log = "=0.4.14" ++ ++attester = {path = "../attestation-agent/attester"} +diff --git a/service/attestation/attestation-service/verifier/Cargo.toml b/service/attestation/attestation-service/verifier/Cargo.toml +new file mode 100644 +index 0000000..d5f2874 +--- /dev/null ++++ b/service/attestation/attestation-service/verifier/Cargo.toml +@@ -0,0 +1,27 @@ ++[package] ++name = "verifier" ++version = "0.1.0" ++edition = "2021" ++ ++[dependencies] ++anyhow.workspace = true ++ciborium-ll.workspace = true ++ciborium-io.workspace = true ++ciborium.workspace = true ++half.workspace = true ++serde.workspace = true ++serde_json.workspace = true ++async-trait.workspace = true ++cose-rust.workspace = true ++hex.workspace = true ++openssl.workspace = true ++log.workspace = true ++ ++attester.workspace = true ++ ++[dev-dependencies] ++ ++[features] ++default = [ "itrustee-verifier","virtcca-verifier" ] ++itrustee-verifier = [] ++virtcca-verifier = ["attester/virtcca-attester"] +diff --git a/service/attestation/attestation-service/verifier/src/itrustee/itrustee.rs b/service/attestation/attestation-service/verifier/src/itrustee/itrustee.rs +new file mode 100644 +index 0000000..9749871 +--- /dev/null ++++ b/service/attestation/attestation-service/verifier/src/itrustee/itrustee.rs +@@ -0,0 +1,53 @@ ++/* automatically generated by rust-bindgen 0.69.4 */ ++ ++#[repr(C)] ++#[derive(Debug, Copy, Clone)] ++pub struct buffer_data { ++ pub size: ::std::os::raw::c_uint, ++ pub buf: *mut ::std::os::raw::c_uchar, ++} ++#[test] ++fn bindgen_test_layout_buffer_data() { ++ const UNINIT: ::std::mem::MaybeUninit = ::std::mem::MaybeUninit::uninit(); ++ let ptr = UNINIT.as_ptr(); ++ assert_eq!( ++ ::std::mem::size_of::(), ++ 16usize, ++ concat!("Size of: ", stringify!(buffer_data)) ++ ); ++ assert_eq!( ++ ::std::mem::align_of::(), ++ 8usize, ++ concat!("Alignment of ", stringify!(buffer_data)) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).size) as usize - ptr as usize }, ++ 0usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(buffer_data), ++ "::", ++ stringify!(size) ++ ) ++ ); ++ assert_eq!( ++ unsafe { ::std::ptr::addr_of!((*ptr).buf) as usize - ptr as usize }, ++ 8usize, ++ concat!( ++ "Offset of field: ", ++ stringify!(buffer_data), ++ "::", ++ stringify!(buf) ++ ) ++ ); ++} ++ ++#[link(name = "teeverifier")] ++extern "C" { ++ pub fn tee_verify_report( ++ data_buf: *mut buffer_data, ++ nonce: *mut buffer_data, ++ type_: ::std::os::raw::c_int, ++ filename: *mut ::std::os::raw::c_char, ++ ) -> ::std::os::raw::c_int; ++} +diff --git a/service/attestation/attestation-service/verifier/src/itrustee/mod.rs b/service/attestation/attestation-service/verifier/src/itrustee/mod.rs +new file mode 100644 +index 0000000..f8038ba +--- /dev/null ++++ b/service/attestation/attestation-service/verifier/src/itrustee/mod.rs +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++//! itrustee verifier plugin ++ ++use super::*; ++use log; ++use std::path::Path; ++ ++mod itrustee; ++ ++const ITRUSTEE_REF_VALUE_FILE: &str = "/etc/attestation/itrustee/basevalue.txt"; ++ ++#[derive(Debug, Default)] ++pub struct ItrusteeVerifier {} ++ ++impl ItrusteeVerifier { ++ pub async fn evaluate(&self, user_data: &[u8], evidence: &[u8]) -> Result<()> { ++ return evalute_wrapper(user_data, evidence); ++ } ++} ++ ++fn evalute_wrapper(user_data: &[u8], evidence: &[u8]) -> Result<()> { ++ let mut in_data = user_data.to_vec(); ++ let mut in_evidence = evidence.to_vec(); ++ let mut data_buf: itrustee::buffer_data = itrustee::buffer_data { ++ size: in_evidence.len() as ::std::os::raw::c_uint, ++ buf: in_evidence.as_mut_ptr() as *mut ::std::os::raw::c_uchar, ++ }; ++ let mut nonce = itrustee::buffer_data { ++ size: in_data.len() as ::std::os::raw::c_uint, ++ buf: in_data.as_mut_ptr() as *mut ::std::os::raw::c_uchar, ++ }; ++ let policy: std::os::raw::c_int = 1; ++ if !Path::new(ITRUSTEE_REF_VALUE_FILE).exists() { ++ log::error!("itrustee verify report {} not exists", ITRUSTEE_REF_VALUE_FILE); ++ bail!("itrustee verify report {} not exists", ITRUSTEE_REF_VALUE_FILE); ++ } ++ let mut ref_file = String::from(ITRUSTEE_REF_VALUE_FILE); ++ let basevalue = ref_file.as_mut_ptr() as *mut ::std::os::raw::c_char; ++ unsafe { ++ let ret = itrustee::tee_verify_report(&mut data_buf, &mut nonce, policy, basevalue); ++ if ret != 0 { ++ log::error!("itrustee verify report failed ret:{}", ret); ++ bail!("itrustee verify report failed ret:{}", ret); ++ } ++ } ++ Ok(()) ++} +diff --git a/service/attestation/attestation-service/verifier/src/lib.rs b/service/attestation/attestation-service/verifier/src/lib.rs +new file mode 100644 +index 0000000..f3c9157 +--- /dev/null ++++ b/service/attestation/attestation-service/verifier/src/lib.rs +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++//! Unified tee verifier ++//! ++//! This crate provides unified APIs to verify TEE evidence. ++ ++use anyhow::*; ++use serde_json; ++use async_trait::async_trait; ++ ++use attester::{Evidence, TeeType}; ++ ++#[cfg(feature = "itrustee-verifier")] ++mod itrustee; ++ ++#[cfg(feature = "virtcca-verifier")] ++mod virtcca; ++ ++#[derive(Debug, Default)] ++pub struct Verifier {} ++ ++#[async_trait] ++pub trait VerifierAPIs { ++ async fn verify_evidence(&self, user_data: &[u8], evidence: &[u8]) -> Result<()>; ++} ++ ++#[async_trait] ++impl VerifierAPIs for Verifier { ++ async fn verify_evidence(&self, user_data: &[u8], evidence: &[u8]) -> Result<()> { ++ let aa_evidence: Evidence = serde_json::from_slice(evidence)?; ++ let tee_type = aa_evidence.tee; ++ let evidence = aa_evidence.evidence.as_bytes(); ++ match tee_type { ++ #[cfg(feature = "itrustee-verifier")] ++ TeeType::Itrustee => itrustee::ItrusteeVerifier::default().evaluate(user_data, evidence).await, ++ #[cfg(feature = "virtcca-verifier")] ++ TeeType::Virtcca => virtcca::VirtCCAVerifier::default().evaluate(user_data, evidence).await, ++ _ => bail!("unsupported tee type:{:?}", tee_type), ++ } ++ } ++} +\ No newline at end of file +diff --git a/service/attestation/attestation-service/verifier/src/virtcca/mod.rs b/service/attestation/attestation-service/verifier/src/virtcca/mod.rs +new file mode 100644 +index 0000000..3994743 +--- /dev/null ++++ b/service/attestation/attestation-service/verifier/src/virtcca/mod.rs +@@ -0,0 +1,373 @@ ++/* ++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved. ++ * secGear is licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ */ ++ ++//! virtcca verifier plugin ++ ++use anyhow::{Result, bail, anyhow}; ++use cose::keys::CoseKey; ++use cose::message::CoseMessage; ++use ciborium; ++use ciborium::value::Value; ++use openssl::rsa; ++use openssl::pkey::Public; ++use openssl::x509; ++use openssl::pkey::PKey; ++use log; ++ ++use attester::virtcca::VirtccaEvidence; ++ ++const VIRTCCA_ROOT_CERT: &str = "/etc/attestation/virtcca/Huawei Equipment Root CA.pem"; ++const VIRTCCA_SUB_CERT: &str = "/etc/attestation/virtcca/Huawei IT Product CA.pem"; ++const VIRTCCA_REF_VALUE_FILE: &str = "/etc/attestation/virtcca/ref_value.json"; ++ ++#[derive(Debug, Default)] ++pub struct VirtCCAVerifier {} ++ ++impl VirtCCAVerifier { ++ pub async fn evaluate(&self, user_data: &[u8], evidence: &[u8]) -> Result<()> { ++ return Evidence::verify(user_data, evidence); ++ } ++} ++ ++const CBOR_TAG: u64 = 399; ++const CVM_LABEL: i128 = 44241; ++ ++const CVM_CHALLENGE_LABEL: i128 = 10; ++const CVM_RPV_LABEL: i128 = 44235; ++const CVM_RIM_LABEL: i128 = 44238; ++const CVM_REM_LABEL: i128 = 44239; ++const CVM_HASH_ALG_LABEL: i128 = 44236; ++const CVM_PUB_KEY_LABEL: i128 = 44237; ++const CVM_PUB_KEY_HASH_ALG_LABEL: i128 = 44240; ++ ++const CVM_CHALLENGE_SIZE: usize = 64; ++const CVM_RPV_SIZE: usize = 64; ++const CVM_REM_ARR_SIZE: usize = 4; ++const CVM_PUB_KEY_SIZE: usize = 550; ++ ++#[derive(Debug)] ++pub struct CvmToken { ++ pub challenge: [u8; CVM_CHALLENGE_SIZE], // 10 => bytes .size 64 ++ pub rpv: [u8; CVM_RPV_SIZE], // 44235 => bytes .size 64 ++ pub rim: Vec, // 44238 => bytes .size {32,48,64} ++ pub rem: [Vec; CVM_REM_ARR_SIZE], // 44239 => [ 4*4 bytes .size {32,48,64} ] ++ pub hash_alg: String, // 44236 => text ++ pub pub_key: [u8; CVM_PUB_KEY_SIZE], // 44237 => bytes .size 550 ++ pub pub_key_hash_alg: String, // 44240 => text ++} ++ ++pub struct Evidence { ++ /// COSE Sign1 envelope for cvm_token ++ pub cvm_envelop: CoseMessage, ++ /// Decoded cvm token ++ pub cvm_token: CvmToken, ++} ++ ++impl Evidence { ++ pub fn new() -> Self { ++ Self { ++ cvm_envelop: CoseMessage::new_sign(), ++ cvm_token: CvmToken::new(), ++ } ++ } ++ pub fn verify(user_data: &[u8], evidence: &[u8]) -> Result<()> { ++ let virtcca_ev: VirtccaEvidence = serde_json::from_slice(evidence)?; ++ let evidence = virtcca_ev.evidence; ++ let dev_cert = virtcca_ev.dev_cert; ++ let mut evidence = Evidence::decode(evidence)?; ++ ++ // verify platform token ++ evidence.verify_platform_token(&dev_cert)?; ++ ++ // verify cvm token ++ evidence.verify_cvm_token(user_data)?; ++ ++ Ok(()) ++ } ++ fn verify_platform_token(&mut self, dev_cert: &[u8]) -> Result<()> { ++ // todo verify platform COSE_Sign1 by dev_cert ++ ++ // verify dev_cet by cert chain ++ Evidence::verify_dev_cert_chain(dev_cert)?; ++ ++ Ok(()) ++ } ++ // todo verify cert chain, now only verify signature ++ fn verify_dev_cert_chain(dev_cert: &[u8]) -> Result<()> { ++ let dev_cert = x509::X509::from_der(dev_cert)?; ++ let sub_cert_file = std::fs::read(VIRTCCA_SUB_CERT)?; ++ let sub_cert = x509::X509::from_pem(&sub_cert_file)?; ++ let root_cert_file = std::fs::read(VIRTCCA_ROOT_CERT)?; ++ let root_cert = x509::X509::from_pem(&root_cert_file)?; ++ ++ // verify dev_cert by sub_cert ++ let ret = dev_cert.verify(&(sub_cert.public_key()? as PKey))?; ++ if !ret { ++ log::error!("verify dev cert by sub cert failed"); ++ bail!("verify dev cert by sub cert failed"); ++ } ++ // verify sub_cert by root_cert ++ let ret = sub_cert.verify(&(root_cert.public_key()? as PKey))?; ++ if !ret { ++ log::error!("verify sub cert by root cert failed"); ++ bail!("verify sub cert by root cert failed"); ++ } ++ // verify self signed root_cert ++ let ret = root_cert.verify(&(root_cert.public_key()? as PKey))?; ++ if !ret { ++ log::error!("verify self signed root cert failed"); ++ bail!("verify self signed root cert failed"); ++ } ++ Ok(()) ++ } ++ fn verify_cvm_token(&mut self, challenge: &[u8]) -> Result<()> { ++ // verify challenge ++ let len = challenge.len(); ++ let token_challenge = &self.cvm_token.challenge[0..len]; ++ if challenge != token_challenge { ++ log::error!("verify cvm token challenge error, cvm_token challenge {:?}, input challenge {:?}", ++ token_challenge, challenge); ++ bail!("verify cvm token challenge error, cvm_token challenge {:?}, input challenge {:?}", ++ token_challenge, challenge); ++ } ++ ++ // todo verify cvm pubkey by platform.challenge ++ ++ // verify COSE_Sign1 signature begin ++ let raw_pub_key = self.cvm_token.pub_key; ++ let mut cose_key: CoseKey = Evidence::from_raw_pub_key(&raw_pub_key)?; ++ cose_key.key_ops(vec![cose::keys::KEY_OPS_VERIFY]); ++ match self.cvm_envelop.header.alg { ++ Some(alg) => cose_key.alg(alg), ++ None => bail!("cose sign verify alg is none"), ++ } ++ self.cvm_envelop.key(&cose_key).map_err(|err| anyhow!("set cose_key to COSE_Sign1 envelop failed: {err:?}"))?; ++ self.cvm_envelop.decode(None, None).map_err(|err| anyhow!("verify COSE_Sign1 signature failed:{err:?}"))?; ++ // verify COSE_Sign1 signature end ++ ++ // verfiy cvm token with reference value ++ self.compare_with_ref()?; ++ ++ Ok(()) ++ } ++ ++ fn compare_with_ref(&mut self) -> Result<()> { ++ let ref_file = std::fs::read(VIRTCCA_REF_VALUE_FILE)?; ++ let js_ref = serde_json::from_slice(&ref_file)?; ++ match js_ref { ++ serde_json::Value::Object(obj) => { ++ for (k, v) in obj { ++ if k == "rim" { ++ let rim_ref = match v { ++ serde_json::Value::String(rim) => rim, ++ _ => bail!("tim ref expecting String"), ++ }; ++ let rim = hex::encode(self.cvm_token.rim.clone()); ++ if rim_ref != rim { ++ log::error!("expecting rim: {}, got: {}", rim_ref, rim); ++ bail!("expecting rim: {}, got: {}", rim_ref, rim); ++ } ++ } ++ } ++ } ++ _ => bail!("invalid json ref value"), ++ } ++ ++ Ok(()) ++ } ++ fn from_raw_pub_key(raw_pub_key: &[u8]) -> Result { ++ let pub_key: rsa::Rsa = rsa::Rsa::public_key_from_der(raw_pub_key)?; ++ let mut cose_key = CoseKey::new(); ++ cose_key.kty(cose::keys::RSA); ++ cose_key.e(pub_key.e().to_vec()); ++ cose_key.n(pub_key.n().to_vec()); ++ ++ Ok(cose_key) ++ } ++ pub fn decode(raw_evidence: Vec) -> Result { ++ let mut evidence: Evidence = Evidence::new(); ++ ++ // decode CBOR evidence to ciborium Value ++ let val: Value = ciborium::de::from_reader(raw_evidence.as_slice())?; ++ log::debug!("[debug] decode CBOR virtcca token to ciborium Value:{:?}", val); ++ println!("[debug] decode CBOR virtcca token to ciborium Value:{:?}", val); ++ if let Value::Tag(t, m) = val { ++ if t != CBOR_TAG { ++ log::error!("input evidence error, expecting tag {}, got {}", CBOR_TAG, t); ++ bail!("input evidence error, expecting tag {}, got {}", CBOR_TAG, t); ++ } ++ if let Value::Map(contents) = *m { ++ for (k, v) in contents.iter() { ++ if let Value::Integer(i) = k { ++ match (*i).into() { ++ CVM_LABEL => evidence.set_cvm_token(v)?, ++ err => bail!("unknown label {}", err), ++ } ++ } else { ++ bail!("expecting integer key"); ++ } ++ } ++ } else { ++ bail!("expecting map type"); ++ } ++ } else { ++ bail!("expecting tag type"); ++ } ++ ++ let ret = evidence.cvm_envelop.init_decoder(None); ++ match ret { ++ Ok(_) => log::info!("decode COSE success"), ++ Err(e) => { ++ log::error!("decode COSE failed, {:?}", e); ++ bail!("decode COSE failed"); ++ }, ++ } ++ ++ // decode cvm CBOR payload ++ evidence.cvm_token = CvmToken::decode(&evidence.cvm_envelop.payload)?; ++ Ok(evidence) ++ } ++ fn set_cvm_token(&mut self, v: &Value) -> Result<()> { ++ let tmp = v.as_bytes(); ++ if tmp.is_none() { ++ log::error!("cvm token is none"); ++ bail!("cvm token is none"); ++ } ++ self.cvm_envelop.bytes = tmp.unwrap().clone(); ++ Ok(()) ++ } ++} ++ ++impl CvmToken { ++ pub fn new() -> Self { ++ Self { ++ challenge: [0; CVM_CHALLENGE_SIZE], ++ rpv: [0; CVM_RPV_SIZE], ++ rim: vec![0, 64], ++ rem: Default::default(), ++ hash_alg: String::from(""), ++ pub_key: [0; CVM_PUB_KEY_SIZE], ++ pub_key_hash_alg: String::from(""), ++ } ++ } ++ pub fn decode(raw_payload: &Vec) -> Result { ++ let payload: Vec = ciborium::de::from_reader(raw_payload.as_slice())?; ++ log::debug!("After decode CBOR payload, payload {:?}", payload); ++ let payload: Value = ciborium::de::from_reader(payload.as_slice())?; ++ log::debug!("After decode CBOR payload agin, payload {:?}", payload); ++ let mut cvm_token: CvmToken = CvmToken::new(); ++ if let Value::Map(contents) = payload { ++ for (k, v) in contents.iter() { ++ if let Value::Integer(i) = k { ++ match (*i).into() { ++ CVM_CHALLENGE_LABEL => cvm_token.set_challenge(v)?, ++ CVM_RPV_LABEL => cvm_token.set_rpv(v)?, ++ CVM_RIM_LABEL => cvm_token.set_rim(v)?, ++ CVM_REM_LABEL => cvm_token.set_rem(v)?, ++ CVM_HASH_ALG_LABEL => cvm_token.set_hash_alg(v)?, ++ CVM_PUB_KEY_LABEL => cvm_token.set_pub_key(v)?, ++ CVM_PUB_KEY_HASH_ALG_LABEL => cvm_token.set_pub_key_hash_alg(v)?, ++ err => bail!("cvm payload unkown label {}", err), ++ } ++ } else { ++ bail!("cvm payload expecting integer key"); ++ } ++ } ++ } else { ++ bail!("expecting cvm payload map type"); ++ } ++ log::debug!("cvm_token decode from raw payload, {:?}", cvm_token); ++ Ok(cvm_token) ++ } ++ fn set_challenge(&mut self, v: &Value) -> Result<()> { ++ let tmp = v.as_bytes(); ++ if tmp.is_none() { ++ bail!("cvm token challenge is none"); ++ } ++ let tmp = tmp.unwrap().clone(); ++ if tmp.len() != CVM_CHALLENGE_SIZE { ++ bail!("cvm token challenge expecting {} bytes, got {}", CVM_CHALLENGE_SIZE,tmp.len()); ++ } ++ self.challenge[..].clone_from_slice(&tmp); ++ Ok(()) ++ } ++ fn set_rpv(&mut self, v: &Value) -> Result<()> { ++ let tmp = v.as_bytes(); ++ if tmp.is_none() { ++ bail!("cvm token rpv is none"); ++ } ++ let tmp = tmp.unwrap().clone(); ++ if tmp.len() != CVM_RPV_SIZE { ++ bail!("cvm token rpv expecting {} bytes, got {}", CVM_RPV_SIZE, tmp.len()); ++ } ++ self.rpv[..].clone_from_slice(&tmp); ++ Ok(()) ++ } ++ fn get_measurement(v: &Value, who: &str) -> Result> { ++ let tmp = v.as_bytes(); ++ if tmp.is_none() { ++ bail!("cvm token {} is none", who); ++ } ++ let tmp = tmp.unwrap().clone(); ++ if !matches!(tmp.len(), 32 | 48 | 64) { ++ bail!("cvm token {} expecting 32, 48 or 64 bytes, got {}", who, tmp.len()); ++ } ++ Ok(tmp) ++ } ++ fn set_rim(&mut self, v: &Value) -> Result<()> { ++ self.rim = Self::get_measurement(v, "rim")?; ++ Ok(()) ++ } ++ fn set_rem(&mut self, v: &Value) -> Result<()> { ++ let tmp = v.as_array(); ++ if tmp.is_none() { ++ bail!("cvm token rem is none"); ++ } ++ let tmp = tmp.unwrap().clone(); ++ if tmp.len() != 4 { ++ bail!("cvm token rem expecting size {}, got {}", CVM_REM_ARR_SIZE, tmp.len()); ++ } ++ ++ for (i, val) in tmp.iter().enumerate() { ++ self.rem[i] = Self::get_measurement(val, "rem[{i}]")?; ++ } ++ Ok(()) ++ } ++ fn get_hash_alg(v: &Value, who: &str) -> Result { ++ let alg = v.as_text(); ++ if alg.is_none() { ++ bail!("{} hash alg must be str", who); ++ } ++ Ok(alg.unwrap().to_string()) ++ } ++ fn set_hash_alg(&mut self, v: &Value) -> Result<()> { ++ self.hash_alg = Self::get_hash_alg(v, "cvm token")?; ++ Ok(()) ++ } ++ fn set_pub_key(&mut self, v: &Value) -> Result<()> { ++ let tmp = v.as_bytes(); ++ if tmp.is_none() { ++ bail!("cvm token pub key is none"); ++ } ++ let tmp = tmp.unwrap().clone(); ++ if tmp.len() != CVM_PUB_KEY_SIZE { ++ bail!("cvm token pub key len expecting {}, got {}", CVM_PUB_KEY_SIZE, tmp.len()); ++ } ++ self.pub_key[..].clone_from_slice(&tmp); ++ Ok(()) ++ } ++ fn set_pub_key_hash_alg(&mut self, v: &Value) -> Result<()> { ++ self.pub_key_hash_alg = Self::get_hash_alg(v, "pub key")?; ++ Ok(()) ++ } ++} ++ +-- +2.33.0 diff --git a/secGear.spec b/secGear.spec index d37a1ef6243afc9cf9c2b02a320368c1057a1058..fe93b44ef3b7f114ff92b88f2824d581b06b6b43 100644 --- a/secGear.spec +++ b/secGear.spec @@ -1,6 +1,6 @@ Name: secGear Version: 0.1.0 -Release: 35 +Release: 36 Summary: secGear is an SDK to develop confidential computing apps based on hardware enclave features @@ -8,6 +8,7 @@ Group: OS Security License: Mulan PSL v2 URL: https://gitee.com/openeuler/secGear Source0: https://gitee.com/openeuler/secGear/repository/archive/v%{version}.tar.gz +Source1: vendor.tar.gz Patch0: 0001-add-README.cn.md.patch Patch1: 0002-it-is-better-to-define-enum-from-0-rather-than-1.patch @@ -80,6 +81,7 @@ Patch67: 0068-bugfix-when-input-empty-hash.patch Patch68: 0069-adapt-sign-tool-to-pass-API_LEVEL.patch Patch69: 0070-sign-tool-add-invalid-param-verify.patch Patch70: 0071-adapt-report-with-request-key.patch +Patch71: backport-init-attestation.patch BuildRequires: gcc python automake autoconf libtool BUildRequires: glibc glibc-devel cmake ocaml-dune rpm gcc-c++ openssl-libs openssl-devel @@ -87,6 +89,7 @@ BUildRequires: glibc glibc-devel cmake ocaml-dune rpm gcc-c++ openssl-libs opens BUildRequires: sgxsdk libsgx-launch libsgx-urts intel-sgx-ssl-devel %else BUildRequires: itrustee_sdk itrustee_sdk-devel +BuildRequires: rust cargo rust-packaging virtCCA_sdk-devel virtCCA_sdk %endif Requires: rsyslog openssl-libs @@ -117,10 +120,27 @@ Summary: simulation package files for %{name} Requires: %{name}%{?isa} = %{version}-%{release} %description sim The %{name}-sim is package contains simulation libraries for developing applications +%else +%package aa +Summary: Attestation agent for %{name} +%description aa +The %{name}-aa is package contains attestation agent + +%package aa-devel +Summary: Development files for %{name} attestation agent +Requires: %{name}%{?isa}-aa = %{version}-%{release} +%description aa-devel +The %{name}-aa-devel is package contains Header file for attestation agent + +%define _cargo /usr/bin/env CARGO_HOME=.cargo RUSTC_BOOTSTRAP=1 /usr/bin/cargo %endif %prep %autosetup -n %{name}-v%{version} -p1 +%ifnarch x86_64 +cd service/attestation/attestation-agent/ +tar xf %{SOURCE1} +%endif %build source ./environment @@ -131,6 +151,18 @@ make %else cmake -DCMAKE_BUILD_TYPE=Debug -DENCLAVE=GP make + +cd service/attestation/attestation-agent/ +mkdir -p .cargo +touch .cargo/config +cat << EOF >> ./.cargo/config +[source.crates-io] +replace-with = "vendored-sources" + +[source.vendored-sources] +directory = "vendor" +EOF +cargo build --features virtcca --lib --release %endif %install @@ -160,6 +192,8 @@ install -pm 644 inc/host_inc/gp/*.edl %{buildroot}/%{_includedir}/secGear install -pm 644 inc/enclave_inc/*.h %{buildroot}/%{_includedir}/secGear install -pm 644 inc/enclave_inc/gp/*.h %{buildroot}/%{_includedir}/secGear install -pm 644 inc/enclave_inc/gp/itrustee/*.h %{buildroot}/%{_includedir}/secGear +install -pm 644 service/attestation/attestation-agent/rust_attestation_agent.h %{buildroot}/%{_includedir} +install -pm 644 service/attestation/attestation-agent/target/release/deps/libattestation_agent.so %{buildroot}/%{_libdir}/libattestation_agent.so %endif install -pm 644 component/remote_attest/ra_report/sg_ra_report.h %{buildroot}/%{_includedir}/secGear install -pm 644 component/remote_attest/ra_verify/sg_ra_report_verify.h %{buildroot}/%{_includedir}/secGear @@ -205,12 +239,21 @@ popd %license License/LICENSE %{_libdir}/libsecgearsim.so %{_libdir}/libsgxsim_0.so +%else +%files aa +%{_libdir}/libattestation_agent.so + +%files aa-devel +%{_includedir}/rust_attestation_agent.h %endif %post systemctl restart rsyslog %changelog +* Tue May 28 2024 zhengxiaoxiao - 0.1.0-36 +- add init-attestation.patch + * Mon Sep 18 2023 wangqingsan - 0.1.0-35 - synchronous features