diff --git a/backport-init-attestation.patch b/backport-init-attestation.patch new file mode 100644 index 0000000000000000000000000000000000000000..8349f2cf438a9c821a755023e1ebd3cc451e1dc0 --- /dev/null +++ b/backport-init-attestation.patch @@ -0,0 +1,1714 @@ +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 three commit points: + +Reference: https://gitee.com/openeuler/secGear/commit/d06b6beab9ae13898870297e8ef2ae806cd8d6d0 + https://gitee.com/openeuler/secGear/commit/b90e039631f1031a485ef038174c0bef831223a5 + https://gitee.com/openeuler/secGear/commit/dad056809c5e94b50c47063d728d5f1e47800512 +Conflict:no +--- + .../attestation/attestation-agent/Cargo.toml | 22 +++ + .../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 +++++++ + .../rust_attestation_agent.h | 56 +++++++ + .../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 +++++++++++++++ + .../attestation-service/Cargo.toml | 19 + + .../attestation-service/verifier/Cargo.toml | 24 ++ + .../verifier/src/itrustee/itrustee.rs | 53 +++ + .../verifier/src/itrustee/mod.rs | 58 +++ + .../attestation-service/verifier/src/lib.rs | 51 +++ + .../verifier/src/virtcca/mod.rs | 392 ++++++++++++++++++ + .../verifier/test_data/virtcca.cbor | 1 + + .../verifier/test_data/virtcca_aik_cert.der | Bin 0 -> 1170 bytes + 23 files changed, 1480 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/rust_attestation_agent.h + 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-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 + create mode 100644 service/attestation/attestation-service/verifier/test_data/virtcca.cbor + create mode 100644 service/attestation/attestation-service/verifier/test_data/virtcca_aik_cert.der + +diff --git a/service/attestation/attestation-agent/Cargo.toml b/service/attestation/attestation-agent/Cargo.toml +new file mode 100644 +index 0000000..b604e0e +--- /dev/null ++++ b/service/attestation/attestation-agent/Cargo.toml +@@ -0,0 +1,22 @@ ++[workspace] ++resolver = "2" ++members = [ ++ "agent", ++ "attester", ++] ++ ++[workspace.dependencies] ++anyhow = "1.0" ++config = "0.14.0" ++serde = { version = "1.0", features = ["derive"] } ++serde_json = "1.0" ++rand = "0.8.5" ++base64-url = "3.0.0" ++async-trait = "0.1.78" ++tokio = "1.0" ++log = "0.4.14" ++env_logger = "0.9" ++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/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-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-service/Cargo.toml b/service/attestation/attestation-service/Cargo.toml +new file mode 100644 +index 0000000..2c132e3 +--- /dev/null ++++ b/service/attestation/attestation-service/Cargo.toml +@@ -0,0 +1,19 @@ ++[workspace] ++resolver = "2" ++members = [ ++ #"service", ++ "verifier", ++] ++ ++[workspace.dependencies] ++anyhow = "1.0" ++serde = "1.0" ++serde_json = "1.0" ++async-trait = "0.1.78" ++cose-rust = "0.1.7" ++ciborium = "0.2.2" ++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..8e45439 +--- /dev/null ++++ b/service/attestation/attestation-service/verifier/Cargo.toml +@@ -0,0 +1,24 @@ ++[package] ++name = "verifier" ++version = "0.1.0" ++edition = "2021" ++ ++[dependencies] ++anyhow.workspace = true ++serde.workspace = true ++serde_json.workspace = true ++async-trait.workspace = true ++cose-rust.workspace = true ++ciborium.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..cc615d5 +--- /dev/null ++++ b/service/attestation/attestation-service/verifier/src/virtcca/mod.rs +@@ -0,0 +1,392 @@ ++/* ++ * 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; ++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); ++ 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(()) ++ } ++} ++ ++#[cfg(test)] ++mod tests { ++ use super::*; ++ use hex; ++ ++ const TEST_VIRTCCA_TOKEN: &[u8; 2862] = include_bytes!("../../test_data/virtcca.cbor"); ++ #[test] ++ fn decode_token() { ++ let token = hex::decode(TEST_VIRTCCA_TOKEN).unwrap(); ++ let dev_cert = std::fs::read("./test_data/virtcca_aik_cert.der").unwrap(); ++ let challenge = Vec::new(); ++ let virtcca_ev = VirtccaEvidence { ++ evidence: token.to_vec(), ++ dev_cert: dev_cert, ++ }; ++ let virtcca_ev = serde_json::to_vec(&virtcca_ev).unwrap(); ++ let r = Evidence::verify(&challenge, &virtcca_ev); ++ assert!(r.is_ok()); ++ } ++} +\ No newline at end of file +diff --git a/service/attestation/attestation-service/verifier/test_data/virtcca.cbor b/service/attestation/attestation-service/verifier/test_data/virtcca.cbor +new file mode 100644 +index 0000000..44ae29d +--- /dev/null ++++ b/service/attestation/attestation-service/verifier/test_data/virtcca.cbor +@@ -0,0 +1 @@ ++d9018fa119acd159058dd28444a1013824a059037f59037ca70a5840783c7f3e50bfffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000072616e646f6d206319accb58400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000019accd59022630820222300d06092a864886f70d01010105000382020f003082020a0282020100c2bc0c4a77b228283ed82c7943feba9f0c934ca7a95a4c34a1fce6ba306a1b2cc7b9df0f38154f26081292399bf6b97e349e344e1a74c70f483e1659116895cbcacdf0ef2800c10b54eac975b4b8b39b176c4c782beee871f4042916c6c01397dc326b3815ad6aa4a155964a2eb062c5c0481216d27c71486fec21749fec90e1a3fa376afb9a660234a93e595c97e71ebb0ef0100b6e4f1abf02d708bea225047b090d1004c28d3e666d7f32c7bc3b9957b0d56ac0f80d2b6cf31cfcbe0dd7477aee1b678fa451027d226b7347101faa4e01482ea69c8024c11c75abe7d1b54af941d8c002ba41de1e80ee7f2a8b6a48d07e82b2884d65f4f1e27024120a7176e6be22661b5753539fc1794b72402446dd6cc1731463f9cb95bce8592c632e752b8e3beabd049fc9f7a5c8182de244cacd64451884a7cfed7cf1facafce3d3a932fb25cfea681a689906525492755177ae28bd7e514d235f212db064f9391c06fa5da8ea30d0ac2f00284d7e8bcdfa14f02d0d921a4e1641d26bdf2c0ef6be9956ef092b1bf48ebf70d7ae617103dee5ff786f06cae262069eecaba313b97452ae56991e0d47ba99f5d9d79f258d576e92d1b47121349a228ca27e319a9df0c10c6df68ab99f6b0224f5256d0374c37c524589ae178edfd9910054b77f44bb8a62593dfebd719145d0d7fb48571eea0a8959058292e3a344ab15b7759da848c1020301000119accc677368612d32353619acd0677368612d32353619acce58207309ec52e2870938ffa6930793d61e55ab982a756111410829d6073f66c7170819accf8458200000000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000000005820000000000000000000000000000000000000000000000000000000000000000058200000000000000000000000000000000000000000000000000000000000000000590200097b122790ef35155bc59d7e3a418f9d77f473d5c43e0f2a148ebd6654a75a43a726b5dd380d996f945aeecaa05369c61b6e7ec8961fb88c582bb163db34a2cbe59e8d8432b0c7f8201a63511238413ae1110767e9871d487f1b1bcfa240627e99e4b36353f7daa31a36cfbf58f94a5fa3ebdbcc87da32867936e2b082fa28bc1f9f08072fa18c7898ac2cd02e37b702847acff415c1973cc09b2a81e7216b1415a2238a37abe349ce83a941641be847d87918855d7f4d85cadb6dab8af29baff2bd3278403f51034da0aac0191af6119f761a8b123a3924892640dd13b451e2d8e57e7ea5ec482defe75eef4d8d63199cdbad1d8cea07e9d7154e0c03cb32573d9e4258b7f7870966f2c1f44b88dfeae4ce5df0f9dd99f9a90c0a13295e11da096f8bc77b6da4d3c1dee89069c01debb05737c7e31ab4c10cd9b17ef33c75d61d2b2ac81c0293c3584125cef755f68a9aa6883c5fce3fc47dab7d987530448ddb7f518498a7c910cc4ad41bbfc3d690dd38463659bba0c7c0f2ee0313a6810b8cce206d1866982ecc768cbcc327ecda758e966722adede25927c9590d40ae3c8afde5d9b682084715c4565dac9b624f028c03ccb2ac53933f46651ae6e2a101dde231ed4da71e2197dffb3b06eac4e01d58df006ed492838f1938fd88b65334b86c6a8ca7761d41fc670a95766cbcf1e18b42bf000f33338abfe7d829a159ab +\ No newline at end of file +diff --git a/service/attestation/attestation-service/verifier/test_data/virtcca_aik_cert.der b/service/attestation/attestation-service/verifier/test_data/virtcca_aik_cert.der +new file mode 100644 +index 0000000000000000000000000000000000000000..9fd390dc786bf5da450cd6fe4c505e9a6b590fd4 +GIT binary patch +literal 1170 +zcmXqLV(BwzVlG?2%*4pVBq-=-=DGQBOp}b;?e3@(2X=ln;AP{~YV&CO&dbQi&B|b4 +zYshWD$;KSY!Y0h*>}SXilm~LSgxNew6U$RG4P_0aK?2OeA`k%u&k%)xqWqN7LH;bbh{^dwPj0 +z-&x_}FVePuy=SWQo+)vZ^FDBn;b8Lr#DzkVGkFi5Outg0*C{aL?T`PLw@wvFKfwK_ +zfY(m@P@37jnT5T-J1bUNtYV7)?HJ8y*|o65m^=UBZ>7DfqE4Q@qJKH_$gWF*JAX5L +z++Py9efQd65odjm6>mN&@$O`~*$ckPC2I^NHWjMfI{r#s@_{{f;$@)( +zt4Se-xysKQdftbeI_7j}B9HMc?kO4`9EyqyxUamv_Rk^x{bJph^?H8)rKYp{H3vNC +zTb_P7MpOHV@VzU%?;85A@#^NS5D*E-$(!_$op0{6l(TzUc3XVmbT02{^2~Vj(}bmV +z*ZQ{fujjwAIXoA;t-dx#sL}cQg=k}DnFnWY-LjUJ-uc)~(c9+LRtM+5s&k%t+t1kO +zaq6Y#y0BA;3hBQ*<8{qSEA;Q|jwrstwv_SdJ+BqXPR~;|Jrq@W_k`!U>ZH??n*Dw6 +zi%b2V)8r7lYRSP!;mCWY$78BC9ALFQ&KfJfthDv>d=Zx)_qQ)Sbeinycf6}~bYd-UvyXyq~&Kq!p6!5dKFf%d#FoBXB`^Z6btPYOA8&zhH#*1L6g^Ie4vEjyoWb-&5}PK;sY9OwBj4!G=15V^lg +zO(U?Xe_qr6pFRec-WVGtZ19^K&vc~6YSW~K^1^4!x81+taV>h~LOFe|=GS~(G +zdZo3~_*Y?`sFG*1`oX>brbX$@<2-qCgWgTObC%nGp4E@}w&&C4xyx;zS^FJab@WE9 +g^7V*=-!309wC9-+xO0;;%T7xzxt-F-4(Bcc026xFMF0Q* + +literal 0 +HcmV?d00001 + +-- +2.27.0 + diff --git a/secGear.spec b/secGear.spec index d37a1ef6243afc9cf9c2b02a320368c1057a1058..005da6fcd64bd94f70cd396f3a309dc4c68400a6 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 @@ -80,7 +80,9 @@ 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: rust cargo rust-packaging BuildRequires: gcc python automake autoconf libtool BUildRequires: glibc glibc-devel cmake ocaml-dune rpm gcc-c++ openssl-libs openssl-devel %ifarch x86_64 @@ -211,6 +213,9 @@ popd 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