1702 lines
58 KiB
Diff
1702 lines
58 KiB
Diff
From d06b6beab9ae13898870297e8ef2ae806cd8d6d0 Mon Sep 17 00:00:00 2001
|
|
From: houmingyong <houmingyong@huawei.com>
|
|
Date: Tue, 28 May 2024 10:25:41 +0800
|
|
Subject: [PATCH] init attestation
|
|
|
|
The current patch incorporates the following 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
|
|
https://gitee.com/openeuler/secGear/commit/8e02b257d9bec81bc557d6431e90448522ad6270
|
|
https://gitee.com/openeuler/secGear/commit/980d0a89d3b1b1a6d280846d6edddabdfd57a635
|
|
https://gitee.com/openeuler/secGear/commit/1fbc825bd34e859f3bc641f6b1b14c106be23433
|
|
https://gitee.com/openeuler/secGear/commit/97f78a21040443796d137ce1739861b66451c7dd
|
|
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 | 84 ++++
|
|
.../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, 1505 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,42 @@
|
|
+[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 = []
|
|
+with_as = []
|
|
+itrustee-attester = ["attester/itrustee-attester"]
|
|
+virtcca-attester = ["attester/virtcca-attester"]
|
|
+all-attester = ["attester/itrustee-attester", "attester/virtcca-attester"]
|
|
+itrustee-verifier = ["verifier/itrustee-verifier"]
|
|
+virtcca-verifier = ["verifier/virtcca-verifier"]
|
|
+all-verifier = ["verifier/itrustee-verifier", "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,145 @@
|
|
+/*
|
|
+ * 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<Vec<u8>>;
|
|
+
|
|
+ /// `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<Vec<u8>> {
|
|
+ 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?;
|
|
+ #[cfg(feature = "with_as")]
|
|
+ let _ret = request_as(challenge, evidence);
|
|
+
|
|
+ return Ok(_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<Self, Self::Error> {
|
|
+ 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<Self> {
|
|
+ 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,73 @@
|
|
+use agent::*;
|
|
+pub mod agent;
|
|
+
|
|
+// c interface
|
|
+use safer_ffi::prelude::*;
|
|
+use futures::executor::block_on;
|
|
+use attester::EvidenceRequest;
|
|
+
|
|
+#[ffi_export]
|
|
+pub fn get_report(c_uuid: Option<&repr_c::String>, c_challenge: Option<&repr_c::Vec<u8>>) -> repr_c::Vec<u8> {
|
|
+ let uuid = match c_uuid {
|
|
+ None => {println!("uuid is null"); return Vec::new().into();},
|
|
+ Some(uuid) => uuid.clone().to_string(),
|
|
+ };
|
|
+ let challenge = match c_challenge {
|
|
+ None => {println!("challenge is null"); return Vec::new().into();},
|
|
+ Some(cha) => cha.clone().to_vec(),
|
|
+ };
|
|
+
|
|
+ let input: EvidenceRequest = EvidenceRequest {
|
|
+ uuid: uuid,
|
|
+ challenge: challenge,
|
|
+ };
|
|
+
|
|
+ let fut = async {
|
|
+ agent::AttestationAgent::default().get_evidence(input).await
|
|
+ };
|
|
+ let report: Vec<u8> = 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: Option<&repr_c::Vec<u8>>, report: Option<&repr_c::Vec<u8>>) -> safer_ffi::libc::c_int {
|
|
+ let challenge = match c_challenge {
|
|
+ None => {println!("challenge is null"); return 1;},
|
|
+ Some(cha) => cha.clone().to_vec(),
|
|
+ };
|
|
+
|
|
+ let report = match report {
|
|
+ None => {println!("report is null"); return 1;},
|
|
+ Some(report) => report.clone().to_vec(),
|
|
+ };
|
|
+
|
|
+ let fut = async {agent::AttestationAgent::default().verify_evidence(
|
|
+ &challenge, &report).await};
|
|
+ let ret = match block_on(fut) {
|
|
+ Ok(_) => return 0,
|
|
+ Err(e) => {
|
|
+ println!("verify report failed {:?}", e);
|
|
+ return 1;
|
|
+ }
|
|
+ };
|
|
+}
|
|
+
|
|
+#[ffi_export]
|
|
+pub fn free_report(report: repr_c::Vec<u8>) {
|
|
+ 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<ra_buffer_data> = ::std::mem::MaybeUninit::uninit();
|
|
+ let ptr = UNINIT.as_ptr();
|
|
+ assert_eq!(
|
|
+ ::std::mem::size_of::<ra_buffer_data>(),
|
|
+ 16usize,
|
|
+ concat!("Size of: ", stringify!(ra_buffer_data))
|
|
+ );
|
|
+ assert_eq!(
|
|
+ ::std::mem::align_of::<ra_buffer_data>(),
|
|
+ 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<String> {
|
|
+ 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<String> {
|
|
+ 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<u8>,
|
|
+}
|
|
+
|
|
+#[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<Vec<u8>>;
|
|
+}
|
|
+
|
|
+#[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<Vec<u8>> {
|
|
+ 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<String> {
|
|
+ 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<u8>,
|
|
+ pub dev_cert: Vec<u8>,
|
|
+}
|
|
+
|
|
+fn virtcca_get_token(challenge: &[u8]) -> Result<VirtccaEvidence> {
|
|
+ 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<max_align_t> = ::std::mem::MaybeUninit::uninit();
|
|
+ let ptr = UNINIT.as_ptr();
|
|
+ assert_eq!(
|
|
+ ::std::mem::size_of::<max_align_t>(),
|
|
+ 32usize,
|
|
+ concat!("Size of: ", stringify!(max_align_t))
|
|
+ );
|
|
+ assert_eq!(
|
|
+ ::std::mem::align_of::<max_align_t>(),
|
|
+ 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<tsi_ctx> = ::std::mem::MaybeUninit::uninit();
|
|
+ let ptr = UNINIT.as_ptr();
|
|
+ assert_eq!(
|
|
+ ::std::mem::size_of::<tsi_ctx>(),
|
|
+ 4usize,
|
|
+ concat!("Size of: ", stringify!(tsi_ctx))
|
|
+ );
|
|
+ assert_eq!(
|
|
+ ::std::mem::align_of::<tsi_ctx>(),
|
|
+ 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 <stddef.h>
|
|
+#include <stdint.h>
|
|
+
|
|
+/** \brief
|
|
+ * Same as [`Vec<T>`][`rust::Vec`], but with guaranteed `#[repr(C)]` layout
|
|
+ */
|
|
+typedef struct Vec_uint8 {
|
|
+ /** <No documentation available> */
|
|
+ uint8_t * ptr;
|
|
+
|
|
+ /** <No documentation available> */
|
|
+ size_t len;
|
|
+
|
|
+ /** <No documentation available> */
|
|
+ size_t cap;
|
|
+} Vec_uint8_t;
|
|
+
|
|
+/** <No documentation available> */
|
|
+void
|
|
+free_report (
|
|
+ Vec_uint8_t report);
|
|
+
|
|
+/** <No documentation available> */
|
|
+Vec_uint8_t
|
|
+get_report (
|
|
+ Vec_uint8_t const * c_uuid,
|
|
+ Vec_uint8_t const * c_challenge);
|
|
+
|
|
+/** <No documentation available> */
|
|
+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<buffer_data> = ::std::mem::MaybeUninit::uninit();
|
|
+ let ptr = UNINIT.as_ptr();
|
|
+ assert_eq!(
|
|
+ ::std::mem::size_of::<buffer_data>(),
|
|
+ 16usize,
|
|
+ concat!("Size of: ", stringify!(buffer_data))
|
|
+ );
|
|
+ assert_eq!(
|
|
+ ::std::mem::align_of::<buffer_data>(),
|
|
+ 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,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.
|
|
+ */
|
|
+
|
|
+//! 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<()>;
|
|
+}
|
|
+
|
|
+const MAX_CHALLENGE_LEN: usize = 64;
|
|
+
|
|
+#[async_trait]
|
|
+impl VerifierAPIs for Verifier {
|
|
+ async fn verify_evidence(&self, user_data: &[u8], evidence: &[u8]) -> Result<()> {
|
|
+ let len = user_data.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);
|
|
+ }
|
|
+ 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<u8>, // 44238 => bytes .size {32,48,64}
|
|
+ pub rem: [Vec<u8>; 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<Public>))?;
|
|
+ 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<Public>))?;
|
|
+ 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<Public>))?;
|
|
+ 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<CoseKey> {
|
|
+ let pub_key: rsa::Rsa<Public> = 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<u8>) -> Result<Evidence> {
|
|
+ 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<u8>) -> Result<CvmToken> {
|
|
+ let payload: Vec<u8> = 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<Vec<u8>> {
|
|
+ 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<String> {
|
|
+ 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
|