From 2183d33ad7eae723730a8f53d644612fe3216c7f Mon Sep 17 00:00:00 2001 From: Xiaocheng Dong Date: Mon, 5 Feb 2024 21:51:43 -0500 Subject: [PATCH] server: combine three servers to one ccnp server Signed-off-by: Xiaocheng Dong --- .github/workflows/pr-check-rust.yaml | 4 +- .gitignore | 3 + api/eventlog-server.proto | 27 - api/measurement-server.proto | 32 - api/quote-server.proto | 30 - .../{quote-server => ccnp-server}/Cargo.toml | 22 +- service/{pod-quote => ccnp-server}/Makefile | 4 +- service/ccnp-server/README.md | 101 +++ .../{quote-server => ccnp-server}/build.rs | 6 +- service/ccnp-server/proto/ccnp-server.proto | 81 ++ service/ccnp-server/src/agent.rs | 169 ++++ service/ccnp-server/src/ccnp_server_pb.rs | 751 ++++++++++++++++++ service/ccnp-server/src/main.rs | 69 ++ service/ccnp-server/src/service.rs | 123 +++ service/eventlog-server/Makefile | 33 - service/eventlog-server/README.md | 131 --- service/eventlog-server/go.mod | 17 - service/eventlog-server/go.sum | 22 - .../proto/eventlog-server.pb.go | 208 ----- .../proto/eventlog-server.proto | 1 - .../proto/eventlog-server_grpc.pb.go | 105 --- service/eventlog-server/resources/tdx.go | 406 ---------- service/eventlog-server/resources/tdx_test.go | 150 ---- service/eventlog-server/resources/tpm.go | 66 -- service/eventlog-server/resources/tpm_test.go | 24 - service/eventlog-server/server/server.go | 151 ---- service/eventlog-server/server/server_test.go | 173 ---- service/measurement-server/Makefile | 33 - service/measurement-server/README.md | 134 ---- service/measurement-server/go.mod | 18 - service/measurement-server/go.sum | 24 - .../proto/measurement-server.pb.go | 213 ----- .../proto/measurement-server.proto | 1 - .../proto/measurement-server_grpc.pb.go | 105 --- service/measurement-server/resources/base.go | 76 -- .../measurement-server/resources/base_test.go | 44 - service/measurement-server/resources/sev.go | 60 -- .../measurement-server/resources/sev_test.go | 32 - service/measurement-server/resources/tdx.go | 212 ----- .../measurement-server/resources/tdx_test.go | 84 -- service/measurement-server/resources/tpm.go | 44 - .../measurement-server/resources/tpm_test.go | 29 - service/measurement-server/server/server.go | 155 ---- .../measurement-server/server/server_test.go | 160 ---- service/pod-quote/Cargo.toml | 37 - service/pod-quote/README.md | 68 -- service/pod-quote/deny.toml | 35 - service/pod-quote/src/kube.rs | 60 -- service/pod-quote/src/pod_quote.rs | 129 --- service/pod-quote/src/tee.rs | 425 ---------- service/pod-quote/tdx_attest/Cargo.toml | 18 - service/pod-quote/tdx_attest/README.md | 1 - .../pod-quote/tdx_attest/src/tdx_attest.rs | 453 ----------- service/quote-server/Makefile | 40 - service/quote-server/README.md | 109 --- service/quote-server/api/quote-server.proto | 30 - service/quote-server/deny.toml | 35 - service/quote-server/src/quote_server.rs | 308 ------- service/quote-server/src/tee.rs | 425 ---------- service/quote-server/tdx_attest/Cargo.toml | 18 - service/quote-server/tdx_attest/README.md | 1 - .../quote-server/tdx_attest/src/tdx_attest.rs | 453 ----------- 62 files changed, 1315 insertions(+), 5663 deletions(-) delete mode 100644 api/eventlog-server.proto delete mode 100644 api/measurement-server.proto delete mode 100644 api/quote-server.proto rename service/{quote-server => ccnp-server}/Cargo.toml (56%) rename service/{pod-quote => ccnp-server}/Makefile (91%) create mode 100644 service/ccnp-server/README.md rename service/{quote-server => ccnp-server}/build.rs (63%) create mode 100644 service/ccnp-server/proto/ccnp-server.proto create mode 100644 service/ccnp-server/src/agent.rs create mode 100644 service/ccnp-server/src/ccnp_server_pb.rs create mode 100644 service/ccnp-server/src/main.rs create mode 100644 service/ccnp-server/src/service.rs delete mode 100644 service/eventlog-server/Makefile delete mode 100644 service/eventlog-server/README.md delete mode 100644 service/eventlog-server/go.mod delete mode 100644 service/eventlog-server/go.sum delete mode 100644 service/eventlog-server/proto/eventlog-server.pb.go delete mode 120000 service/eventlog-server/proto/eventlog-server.proto delete mode 100644 service/eventlog-server/proto/eventlog-server_grpc.pb.go delete mode 100644 service/eventlog-server/resources/tdx.go delete mode 100644 service/eventlog-server/resources/tdx_test.go delete mode 100644 service/eventlog-server/resources/tpm.go delete mode 100644 service/eventlog-server/resources/tpm_test.go delete mode 100644 service/eventlog-server/server/server.go delete mode 100644 service/eventlog-server/server/server_test.go delete mode 100644 service/measurement-server/Makefile delete mode 100644 service/measurement-server/README.md delete mode 100644 service/measurement-server/go.mod delete mode 100644 service/measurement-server/go.sum delete mode 100644 service/measurement-server/proto/measurement-server.pb.go delete mode 120000 service/measurement-server/proto/measurement-server.proto delete mode 100644 service/measurement-server/proto/measurement-server_grpc.pb.go delete mode 100644 service/measurement-server/resources/base.go delete mode 100644 service/measurement-server/resources/base_test.go delete mode 100644 service/measurement-server/resources/sev.go delete mode 100644 service/measurement-server/resources/sev_test.go delete mode 100644 service/measurement-server/resources/tdx.go delete mode 100644 service/measurement-server/resources/tdx_test.go delete mode 100644 service/measurement-server/resources/tpm.go delete mode 100644 service/measurement-server/resources/tpm_test.go delete mode 100644 service/measurement-server/server/server.go delete mode 100644 service/measurement-server/server/server_test.go delete mode 100644 service/pod-quote/Cargo.toml delete mode 100644 service/pod-quote/README.md delete mode 100644 service/pod-quote/deny.toml delete mode 100644 service/pod-quote/src/kube.rs delete mode 100644 service/pod-quote/src/pod_quote.rs delete mode 100644 service/pod-quote/src/tee.rs delete mode 100644 service/pod-quote/tdx_attest/Cargo.toml delete mode 100644 service/pod-quote/tdx_attest/README.md delete mode 100644 service/pod-quote/tdx_attest/src/tdx_attest.rs delete mode 100644 service/quote-server/Makefile delete mode 100644 service/quote-server/README.md delete mode 100644 service/quote-server/api/quote-server.proto delete mode 100644 service/quote-server/deny.toml delete mode 100644 service/quote-server/src/quote_server.rs delete mode 100644 service/quote-server/src/tee.rs delete mode 100644 service/quote-server/tdx_attest/Cargo.toml delete mode 100644 service/quote-server/tdx_attest/README.md delete mode 100644 service/quote-server/tdx_attest/src/tdx_attest.rs diff --git a/.github/workflows/pr-check-rust.yaml b/.github/workflows/pr-check-rust.yaml index f7b0d8b..47925cf 100644 --- a/.github/workflows/pr-check-rust.yaml +++ b/.github/workflows/pr-check-rust.yaml @@ -30,12 +30,10 @@ jobs: sudo apt update && yes | DEBIAN_FRONTEND=noninteractive sudo apt install -y libcryptsetup-dev clang protobuf-compiler protobuf-c-compiler libprotobuf-c-dev libprotobuf-c1 build-essential pkg-config libssl-dev - name: Run cargo check run: | - cd service/quote-server + cd service/ccnp-server cargo test cargo check cargo fmt -- --check cargo clippy cargo install --locked cargo-deny cargo deny check - cd tdx_attest - cargo test diff --git a/.gitignore b/.gitignore index b25a5fb..52cb214 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ tools/cvm-image-rewriter/pre-stage/05-readonly-data/cloud-init/x-shellscript/01- tools/cvm-image-rewriter/pre-stage/07-install-mvp-guest/cloud-init/ tools/cvm-image-rewriter/pre-stage/07-install-mvp-guest/artifacts/* +service/ccnp-server/target/ +service/ccnp-server/Cargo.lock +service/ccnp-server/.cargo diff --git a/api/eventlog-server.proto b/api/eventlog-server.proto deleted file mode 100644 index 2d17846..0000000 --- a/api/eventlog-server.proto +++ /dev/null @@ -1,27 +0,0 @@ -syntax = "proto3"; -option go_package = "github.com/intel/confidential-cloud-native-primitives/service/eventlog-server/proto/getEventlog"; - -enum CATEGORY { - TDX_EVENTLOG = 0; - TPM_EVENTLOG = 1; -} - -enum LEVEL { - PAAS = 0; - SAAS = 1; -} - -message GetEventlogRequest { - LEVEL eventlog_level = 1; - CATEGORY eventlog_category = 2; - int32 start_position = 3; - int32 count = 4; -} - -message GetEventlogReply { - string eventlog_data_loc = 1; -} - -service Eventlog { - rpc GetEventlog (GetEventlogRequest) returns (GetEventlogReply) {} -} diff --git a/api/measurement-server.proto b/api/measurement-server.proto deleted file mode 100644 index cb9af2e..0000000 --- a/api/measurement-server.proto +++ /dev/null @@ -1,32 +0,0 @@ -syntax = "proto3"; -option go_package = "github.com/intel/confidential-cloud-native-primitives/service/measurement-server/proto/getMeasurement"; - -package measurement; - - -enum TYPE { - PAAS = 0; - SAAS = 1; -} - -enum CATEGORY { - TEE_REPORT = 0; - TPM = 1; - TDX_RTMR = 2; -} - -message GetMeasurementRequest { - TYPE measurement_type = 1; - CATEGORY measurement_category = 2; - string report_data = 3; - int32 register_index = 4; - -} - -message GetMeasurementReply { - string measurement = 1; -} - -service Measurement { - rpc GetMeasurement (GetMeasurementRequest) returns (GetMeasurementReply) {} -} diff --git a/api/quote-server.proto b/api/quote-server.proto deleted file mode 100644 index 4178e80..0000000 --- a/api/quote-server.proto +++ /dev/null @@ -1,30 +0,0 @@ -syntax = "proto3"; -package quoteserver; - -message HealthCheckRequest { - string service = 1; -} - -message HealthCheckResponse { - enum ServingStatus { - UNKNOWN = 0; - SERVING = 1; - NOT_SERVING = 2; - SERVICE_UNKNOWN = 3; - } - ServingStatus status = 1; -} - -service GetQuote { - rpc GetQuote (GetQuoteRequest) returns (GetQuoteResponse); -} - -message GetQuoteRequest { - string user_data = 1; - string nonce = 2; -} - -message GetQuoteResponse { - string quote = 1; - string quote_type = 2; -} diff --git a/service/quote-server/Cargo.toml b/service/ccnp-server/Cargo.toml similarity index 56% rename from service/quote-server/Cargo.toml rename to service/ccnp-server/Cargo.toml index 5608055..90daf06 100644 --- a/service/quote-server/Cargo.toml +++ b/service/ccnp-server/Cargo.toml @@ -1,11 +1,11 @@ [package] -name = "quoteServer" -version = "0.1.0" +name = "ccnp_server" +version = "0.3.2" edition = "2021" [[bin]] # Bin to run the quote server -name = "quote_server" -path = "src/quote_server.rs" +name = "ccnp_server" +path = "src/main.rs" [dependencies] tonic = "0.9" @@ -16,17 +16,19 @@ anyhow = "1.0" async-trait = "0.1.56" base64 = "0.13.0" log = "0.4.14" -serde_json = "1.0" -sha2 = "0.10" clap = { version = "4.0.29", features = ["derive"] } tonic-reflection = "0.9.2" tonic-health = "0.9.2" -nix = "0.26.2" -tdx_attest = "0.1.1" +lazy_static = "1.4.0" +cctrusted_vm = { git="https://github.com/cc-api/cc-trusted-api" } +cctrusted_base = { git="https://github.com/cc-api/cc-trusted-api" } +env_logger = "0.10.1" +regex = "1.10.3" +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.9.30" +openssl = "0.10.63" [dev-dependencies] -tower = { version = "0.4", features = ["util"] } -hyper = { version ="0.14.27" } serial_test = { version ="2.0.0" } [build-dependencies] diff --git a/service/pod-quote/Makefile b/service/ccnp-server/Makefile similarity index 91% rename from service/pod-quote/Makefile rename to service/ccnp-server/Makefile index e6d9aeb..0c4112e 100644 --- a/service/pod-quote/Makefile +++ b/service/ccnp-server/Makefile @@ -10,9 +10,9 @@ DESTDIR ?= $(PREFIX)/bin DEBUG ?= TARGET_DIR := target -BIN_NAME := pod_quote +BIN_NAME := ccnp_server -CARGO := /usr/local/cargo/bin/cargo +CARGO := cargo ifdef DEBUG release := diff --git a/service/ccnp-server/README.md b/service/ccnp-server/README.md new file mode 100644 index 0000000..8bf03d8 --- /dev/null +++ b/service/ccnp-server/README.md @@ -0,0 +1,101 @@ +# CCNP Service + +This service will provide CC event log/CC measurement/CC report by [CC Trusted API](https://github.com/cc-api/cc-trusted-api) for remote attestation service to verify the integrity and confidentiality of the trusted computing environment and required software environment. + +## Start Service + +Run the command: + +``` +sudo ./ccnp_server +[2024-02-06T02:06:18Z INFO ccnp_server] [ccnp-server]: set sock file permissions: /run/ccnp/uds/ccnp-server.sock +[2024-02-06T02:06:18Z INFO ccnp_server] [ccnp-server]: staring the service... +``` + +## Query Information + +1. Query the CC report + +Run the command: + +``` +grpcurl -authority "dummy" -plaintext -d '{ "user_data": "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4", "nonce":"IXUKoBO1UM3c1wopN4sY" }' -unix /run/ccnp/uds/ccnp-server.sock ccnp_server_pb.ccnp.GetCcReport +``` + +The output looks like this: + +``` +{ + "ccType": 1, + "ccReport": "..." +} +``` + +2. Query the CC measurement + +Run the command: + +``` +grpcurl -authority "dummy" -plaintext -d '{ "index": 0, "algo_id": 12}' -unix /run/ccnp/uds/ccnp-server.sock ccnp_server_pb.ccnp.GetCcMeasurement +``` + +The output looks like: + +``` +{ + "measurement": { + "algoId": 12, + "hash": "..." + } +} +``` + +3. Query the eventlog + +Run the command: + +``` +grpcurl -authority "dummy" -plaintext -d '{"start": 0, "count": 3}' -unix /run/ccnp/uds/ccnp-server.sock ccnp_server_pb.ccnp.GetCcEventlog +``` + +The output looks like: + +``` +{ + "eventLogs": [ + { + "eventType": 3, + "digests": [ + { + "algoId": 4, + "hash": "..." + } + ], + "eventSize": 33, + "event": "..." + }, + { + "eventType": 2147483659, + "digests": [ + { + "algoId": 12, + "hash": "..." + } + ], + "eventSize": 42, + "event": "..." + }, + { + "eventType": 2147483658, + "digests": [ + { + "algoId": 12, + "hash": "..." + } + ], + "eventSize": 58, + "event": "..." + } + ] +} +``` diff --git a/service/quote-server/build.rs b/service/ccnp-server/build.rs similarity index 63% rename from service/quote-server/build.rs rename to service/ccnp-server/build.rs index f54a03c..5fdf926 100644 --- a/service/quote-server/build.rs +++ b/service/ccnp-server/build.rs @@ -7,15 +7,15 @@ use std::env; use std::path::PathBuf; fn main() -> Result<(), Box> { - tonic_build::compile_protos("api/quote-server.proto")?; + tonic_build::compile_protos("proto/ccnp-server.proto")?; let original_out_dir = PathBuf::from(env::var("OUT_DIR")?); let out_dir = "./src"; tonic_build::configure() .out_dir(out_dir) - .file_descriptor_set_path(original_out_dir.join("quote_server_descriptor.bin")) - .compile(&["api/quote-server.proto"], &["api"])?; + .file_descriptor_set_path(original_out_dir.join("ccnp_server_descriptor.bin")) + .compile(&["proto/ccnp-server.proto"], &["proto"])?; Ok(()) } diff --git a/service/ccnp-server/proto/ccnp-server.proto b/service/ccnp-server/proto/ccnp-server.proto new file mode 100644 index 0000000..a444f60 --- /dev/null +++ b/service/ccnp-server/proto/ccnp-server.proto @@ -0,0 +1,81 @@ +syntax = "proto3"; +package ccnp_server_pb; + +message HealthCheckRequest { + string service = 1; +} + +message HealthCheckResponse { + enum ServingStatus { + UNKNOWN = 0; + SERVING = 1; + NOT_SERVING = 2; + SERVICE_UNKNOWN = 3; + } + ServingStatus status = 1; +} + +service ccnp { + rpc GetDefaultAlgorithm(GetDefaultAlgorithmRequest) returns (GetDefaultAlgorithmResponse); + rpc GetMeasurementCount(GetMeasurementCountRequest) returns (GetMeasurementCountResponse); + rpc GetCcReport (GetCcReportRequest) returns (GetCcReportResponse); + rpc GetCcMeasurement (GetCcMeasurementRequest) returns (GetCcMeasurementResponse) {} + rpc GetCcEventlog (GetCcEventlogRequest) returns (GetCcEventlogResponse) {} +} + +message GetDefaultAlgorithmRequest { +} + +message GetDefaultAlgorithmResponse { + uint32 algo_id = 1; +} + +message GetMeasurementCountRequest { +} + +message GetMeasurementCountResponse { + uint32 count = 1; +} + +message GetCcReportRequest { + string user_data = 1; + string nonce = 2; +} + +message GetCcReportResponse { + int32 cc_type = 1; + bytes cc_report = 2; +} + +message GetCcMeasurementRequest { + uint32 index = 1; + uint32 algo_id = 2; +} + +message GetCcMeasurementResponse { + TcgDigest measurement = 1; +} + +message GetCcEventlogRequest { + uint32 start = 1; + uint32 count = 2; +} + +message TcgDigest { + uint32 algo_id = 1; + bytes hash = 2; +} + +message TcgEventlog { + uint32 rec_num = 1; + uint32 imr_index = 2; + uint32 event_type = 3; + repeated TcgDigest digests = 4; + uint32 event_size = 5; + bytes event = 6; + map extra_info = 7; +} + +message GetCcEventlogResponse { + repeated TcgEventlog event_logs = 1; +} diff --git a/service/ccnp-server/src/agent.rs b/service/ccnp-server/src/agent.rs new file mode 100644 index 0000000..1f293cd --- /dev/null +++ b/service/ccnp-server/src/agent.rs @@ -0,0 +1,169 @@ +use anyhow::{anyhow, Error}; +use cctrusted_base::{api::CCTrustedApi, api_data::ExtraArgs, tcg}; +use cctrusted_vm::sdk::API; +use log::info; +use std::collections::HashMap; + +use crate::ccnp_pb::{TcgDigest, TcgEventlog}; + +pub struct Agent { + pub event_logs: Option>, +} + +impl Agent { + pub fn init(&mut self) -> Result<(), Error> { + self.event_logs = Some(vec![]); + self.fetch_all_event_logs() + } + + pub fn get_default_algorithm(&mut self) -> Result { + let algo = match API::get_default_algorithm() { + Ok(v) => v, + Err(e) => return Err(e), + }; + Ok(algo.algo_id.into()) + } + + pub fn get_measurement_count(&mut self) -> Result { + let count = match API::get_measurement_count() { + Ok(v) => v, + Err(e) => return Err(e), + }; + + Ok(count.into()) + } + + pub fn fetch_all_event_logs(&mut self) -> Result<(), Error> { + let start: u32 = self + .event_logs + .as_ref() + .expect("The event_logs is None.") + .len() as u32; + + let entries = match API::get_cc_eventlog(Some(start), None) { + Ok(v) => v, + Err(e) => return Err(e), + }; + + if entries.is_empty() { + return Ok(()); + } + + for entry in entries { + match entry { + tcg::EventLogEntry::TcgImrEvent(event) => { + let mut digests: Vec = vec![]; + for d in event.digests { + digests.push(TcgDigest { + algo_id: d.algo_id as u32, + hash: d.hash, + }) + } + let tcg_event = TcgEventlog { + rec_num: 0, + imr_index: event.imr_index, + event_type: event.event_type, + event_size: event.event_size, + event: event.event, + digests, + extra_info: HashMap::new(), + }; + + self.event_logs + .as_mut() + .expect("Change eventlog to mut failed.") + .push(tcg_event) + } + tcg::EventLogEntry::TcgPcClientImrEvent(event) => { + let mut digests: Vec = vec![]; + let algo_id = tcg::TcgDigest::get_algorithm_id_from_digest_size( + event.digest.len().try_into().unwrap(), + ); + + digests.push(TcgDigest { + algo_id: algo_id.into(), + hash: event.digest.to_vec(), + }); + self.event_logs + .as_mut() + .expect("Change eventlog to mut failed.") + .push(TcgEventlog { + rec_num: 0, + imr_index: event.imr_index, + event_type: event.event_type, + event_size: event.event_size, + event: event.event, + digests, + extra_info: HashMap::new(), + }) + } + tcg::EventLogEntry::TcgCanonicalEvent(_event) => { + todo!(); + } + } + } + info!( + "Loaded {} event logs.", + self.event_logs + .as_ref() + .expect("Change eventlog to ref failed.") + .len() + ); + + Ok(()) + } + + pub fn get_cc_eventlog(&mut self, start: u32, count: u32) -> Result, Error> { + let _ = self.fetch_all_event_logs(); + let event_logs = self + .event_logs + .as_ref() + .expect("The eventlog is None.") + .to_vec(); + let s: usize = start.try_into().unwrap(); + let mut e: usize = (start + count).try_into().unwrap(); + + if s >= event_logs.len() { + return Err(anyhow!( + "Invalid input start. Start must be smaller than total event log count." + )); + } + if e >= event_logs.len() { + return Err(anyhow!( + "Invalid input count. count must be smaller than total event log count." + )); + } + if e == 0 { + e = event_logs.len(); + } + + Ok(event_logs[s..e].to_vec().clone()) + } + + pub fn get_cc_report( + &mut self, + nonce: String, + user_data: String, + ) -> Result<(Vec, i32), Error> { + let (report, cc_type) = match API::get_cc_report(Some(nonce), Some(user_data), ExtraArgs {}) + { + Ok(v) => (v.cc_report, v.cc_type as i32), + Err(e) => return Err(e), + }; + + Ok((report, cc_type)) + } + + pub fn get_cc_measurement(&mut self, index: u32, algo_id: u32) -> Result { + let measurement = + match API::get_cc_measurement(index.try_into().unwrap(), algo_id.try_into().unwrap()) { + Ok(v) => TcgDigest { + algo_id: v.algo_id.into(), + hash: v.hash, + }, + Err(e) => return Err(e), + }; + + Ok(measurement) + } +} diff --git a/service/ccnp-server/src/ccnp_server_pb.rs b/service/ccnp-server/src/ccnp_server_pb.rs new file mode 100644 index 0000000..9f0f6df --- /dev/null +++ b/service/ccnp-server/src/ccnp_server_pb.rs @@ -0,0 +1,751 @@ +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HealthCheckRequest { + #[prost(string, tag = "1")] + pub service: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct HealthCheckResponse { + #[prost(enumeration = "health_check_response::ServingStatus", tag = "1")] + pub status: i32, +} +/// Nested message and enum types in `HealthCheckResponse`. +pub mod health_check_response { + #[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration + )] + #[repr(i32)] + pub enum ServingStatus { + Unknown = 0, + Serving = 1, + NotServing = 2, + ServiceUnknown = 3, + } + impl ServingStatus { + /// String value of the enum field names used in the ProtoBuf definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the ProtoBuf definition does not change) and safe for programmatic use. + pub fn as_str_name(&self) -> &'static str { + match self { + ServingStatus::Unknown => "UNKNOWN", + ServingStatus::Serving => "SERVING", + ServingStatus::NotServing => "NOT_SERVING", + ServingStatus::ServiceUnknown => "SERVICE_UNKNOWN", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNKNOWN" => Some(Self::Unknown), + "SERVING" => Some(Self::Serving), + "NOT_SERVING" => Some(Self::NotServing), + "SERVICE_UNKNOWN" => Some(Self::ServiceUnknown), + _ => None, + } + } + } +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetDefaultAlgorithmRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetDefaultAlgorithmResponse { + #[prost(uint32, tag = "1")] + pub algo_id: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetMeasurementCountRequest {} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetMeasurementCountResponse { + #[prost(uint32, tag = "1")] + pub count: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetCcReportRequest { + #[prost(string, tag = "1")] + pub user_data: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub nonce: ::prost::alloc::string::String, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetCcReportResponse { + #[prost(int32, tag = "1")] + pub cc_type: i32, + #[prost(bytes = "vec", tag = "2")] + pub cc_report: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetCcMeasurementRequest { + #[prost(uint32, tag = "1")] + pub index: u32, + #[prost(uint32, tag = "2")] + pub algo_id: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetCcMeasurementResponse { + #[prost(message, optional, tag = "1")] + pub measurement: ::core::option::Option, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetCcEventlogRequest { + #[prost(uint32, tag = "1")] + pub start: u32, + #[prost(uint32, tag = "2")] + pub count: u32, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TcgDigest { + #[prost(uint32, tag = "1")] + pub algo_id: u32, + #[prost(bytes = "vec", tag = "2")] + pub hash: ::prost::alloc::vec::Vec, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct TcgEventlog { + #[prost(uint32, tag = "1")] + pub rec_num: u32, + #[prost(uint32, tag = "2")] + pub imr_index: u32, + #[prost(uint32, tag = "3")] + pub event_type: u32, + #[prost(message, repeated, tag = "4")] + pub digests: ::prost::alloc::vec::Vec, + #[prost(uint32, tag = "5")] + pub event_size: u32, + #[prost(bytes = "vec", tag = "6")] + pub event: ::prost::alloc::vec::Vec, + #[prost(map = "string, string", tag = "7")] + pub extra_info: ::std::collections::HashMap< + ::prost::alloc::string::String, + ::prost::alloc::string::String, + >, +} +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct GetCcEventlogResponse { + #[prost(message, repeated, tag = "1")] + pub event_logs: ::prost::alloc::vec::Vec, +} +/// Generated client implementations. +pub mod ccnp_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + use tonic::codegen::http::Uri; + #[derive(Debug, Clone)] + pub struct CcnpClient { + inner: tonic::client::Grpc, + } + impl CcnpClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } + } + impl CcnpClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + Send + 'static, + ::Error: Into + Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> CcnpClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + , + >>::Error: Into + Send + Sync, + { + CcnpClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + pub async fn get_default_algorithm( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ccnp_server_pb.ccnp/GetDefaultAlgorithm", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("ccnp_server_pb.ccnp", "GetDefaultAlgorithm")); + self.inner.unary(req, path, codec).await + } + pub async fn get_measurement_count( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ccnp_server_pb.ccnp/GetMeasurementCount", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("ccnp_server_pb.ccnp", "GetMeasurementCount")); + self.inner.unary(req, path, codec).await + } + pub async fn get_cc_report( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ccnp_server_pb.ccnp/GetCcReport", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("ccnp_server_pb.ccnp", "GetCcReport")); + self.inner.unary(req, path, codec).await + } + pub async fn get_cc_measurement( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ccnp_server_pb.ccnp/GetCcMeasurement", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("ccnp_server_pb.ccnp", "GetCcMeasurement")); + self.inner.unary(req, path, codec).await + } + pub async fn get_cc_eventlog( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/ccnp_server_pb.ccnp/GetCcEventlog", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("ccnp_server_pb.ccnp", "GetCcEventlog")); + self.inner.unary(req, path, codec).await + } + } +} +/// Generated server implementations. +pub mod ccnp_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::*; + /// Generated trait containing gRPC methods that should be implemented for use with CcnpServer. + #[async_trait] + pub trait Ccnp: Send + Sync + 'static { + async fn get_default_algorithm( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_measurement_count( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_cc_report( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_cc_measurement( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn get_cc_eventlog( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + } + #[derive(Debug)] + pub struct CcnpServer { + inner: _Inner, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, + } + struct _Inner(Arc); + impl CcnpServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + let inner = _Inner(inner); + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } + } + impl tonic::codegen::Service> for CcnpServer + where + T: Ccnp, + B: Body + Send + 'static, + B::Error: Into + Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + let inner = self.inner.clone(); + match req.uri().path() { + "/ccnp_server_pb.ccnp/GetDefaultAlgorithm" => { + #[allow(non_camel_case_types)] + struct GetDefaultAlgorithmSvc(pub Arc); + impl< + T: Ccnp, + > tonic::server::UnaryService + for GetDefaultAlgorithmSvc { + type Response = super::GetDefaultAlgorithmResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_default_algorithm(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetDefaultAlgorithmSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ccnp_server_pb.ccnp/GetMeasurementCount" => { + #[allow(non_camel_case_types)] + struct GetMeasurementCountSvc(pub Arc); + impl< + T: Ccnp, + > tonic::server::UnaryService + for GetMeasurementCountSvc { + type Response = super::GetMeasurementCountResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_measurement_count(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetMeasurementCountSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ccnp_server_pb.ccnp/GetCcReport" => { + #[allow(non_camel_case_types)] + struct GetCcReportSvc(pub Arc); + impl tonic::server::UnaryService + for GetCcReportSvc { + type Response = super::GetCcReportResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_cc_report(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetCcReportSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ccnp_server_pb.ccnp/GetCcMeasurement" => { + #[allow(non_camel_case_types)] + struct GetCcMeasurementSvc(pub Arc); + impl< + T: Ccnp, + > tonic::server::UnaryService + for GetCcMeasurementSvc { + type Response = super::GetCcMeasurementResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_cc_measurement(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetCcMeasurementSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/ccnp_server_pb.ccnp/GetCcEventlog" => { + #[allow(non_camel_case_types)] + struct GetCcEventlogSvc(pub Arc); + impl< + T: Ccnp, + > tonic::server::UnaryService + for GetCcEventlogSvc { + type Response = super::GetCcEventlogResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + (*inner).get_cc_eventlog(request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let inner = inner.0; + let method = GetCcEventlogSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => { + Box::pin(async move { + Ok( + http::Response::builder() + .status(200) + .header("grpc-status", "12") + .header("content-type", "application/grpc") + .body(empty_body()) + .unwrap(), + ) + }) + } + } + } + } + impl Clone for CcnpServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } + } + impl Clone for _Inner { + fn clone(&self) -> Self { + Self(Arc::clone(&self.0)) + } + } + impl std::fmt::Debug for _Inner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } + } + impl tonic::server::NamedService for CcnpServer { + const NAME: &'static str = "ccnp_server_pb.ccnp"; + } +} diff --git a/service/ccnp-server/src/main.rs b/service/ccnp-server/src/main.rs new file mode 100644 index 0000000..8f33eef --- /dev/null +++ b/service/ccnp-server/src/main.rs @@ -0,0 +1,69 @@ +pub mod agent; +pub mod service; +pub mod ccnp_pb { + tonic::include_proto!("ccnp_server_pb"); + + pub const FILE_DESCRIPTOR_SET: &[u8] = + tonic::include_file_descriptor_set!("ccnp_server_descriptor"); +} + +use anyhow::Result; +use clap::Parser; +use log::info; +use std::{fs, os::unix::fs::PermissionsExt}; +use tokio::net::UnixListener; +use tokio_stream::wrappers::UnixListenerStream; +use tonic::transport::Server; + +use ccnp_pb::{ccnp_server::CcnpServer, FILE_DESCRIPTOR_SET}; +use service::Service; + +#[derive(Parser)] +struct Cli { + /// UDS sock file + #[arg(short, long)] + #[clap(default_value = "/run/ccnp/uds/ccnp-server.sock")] + sock: String, +} + +fn set_sock_perm(sock: &str) -> Result<()> { + let mut perms = fs::metadata(sock)?.permissions(); + perms.set_mode(0o666); + fs::set_permissions(sock, perms)?; + Ok(()) +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + env_logger::init_from_env(env_logger::Env::new().default_filter_or("info")); + + let cli = Cli::parse(); + let sock = cli.sock; + + let _ = std::fs::remove_file(sock.clone()); + let uds = match UnixListener::bind(sock.clone()) { + Ok(r) => r, + Err(e) => panic!("[ccnp-server]: bind UDS socket error: {:?}", e), + }; + let uds_stream = UnixListenerStream::new(uds); + info!("[ccnp-server]: set sock file permissions: {}", sock); + set_sock_perm(&sock.clone())?; + + let (mut health_reporter, health_service) = tonic_health::server::health_reporter(); + health_reporter.set_serving::>().await; + + let reflection_service = tonic_reflection::server::Builder::configure() + .register_encoded_file_descriptor_set(FILE_DESCRIPTOR_SET) + .build() + .unwrap(); + + info!("[ccnp-server]: staring the service..."); + let service = Service::new(); + Server::builder() + .add_service(reflection_service) + .add_service(health_service) + .add_service(CcnpServer::new(service)) + .serve_with_incoming(uds_stream) + .await?; + Ok(()) +} diff --git a/service/ccnp-server/src/service.rs b/service/ccnp-server/src/service.rs new file mode 100644 index 0000000..32fd033 --- /dev/null +++ b/service/ccnp-server/src/service.rs @@ -0,0 +1,123 @@ +use anyhow::Result; +use lazy_static::lazy_static; +use std::sync::Mutex; +use tonic::{Request, Response, Status}; + +use crate::{ + agent::Agent, + ccnp_pb::{ + ccnp_server::Ccnp, GetCcEventlogRequest, GetCcEventlogResponse, GetCcMeasurementRequest, + GetCcMeasurementResponse, GetCcReportRequest, GetCcReportResponse, + GetDefaultAlgorithmRequest, GetDefaultAlgorithmResponse, GetMeasurementCountRequest, + GetMeasurementCountResponse, + }, +}; + +lazy_static! { + static ref AGENT: Mutex = Mutex::new(Agent { event_logs: None }); +} + +pub struct Service; +impl Service { + pub fn new() -> Service { + match AGENT.lock().expect("Agent lock() failed.").init() { + Err(e) => panic!("Server panic {:?}", e), + Ok(_v) => _v, + } + Service {} + } +} + +impl Default for Service { + fn default() -> Self { + Self::new() + } +} + +#[tonic::async_trait] +impl Ccnp for Service { + async fn get_default_algorithm( + &self, + _request: Request, + ) -> Result, Status> { + let algo_id = match AGENT + .lock() + .expect("Agent lock() failed.") + .get_default_algorithm() + { + Ok(v) => v, + Err(e) => return Err(Status::internal(e.to_string())), + }; + + Ok(Response::new(GetDefaultAlgorithmResponse { algo_id })) + } + + async fn get_measurement_count( + &self, + _request: Request, + ) -> Result, Status> { + let count = match AGENT + .lock() + .expect("Agent lock() failed.") + .get_measurement_count() + { + Ok(v) => v, + Err(e) => return Err(Status::internal(e.to_string())), + }; + + Ok(Response::new(GetMeasurementCountResponse { count })) + } + + async fn get_cc_measurement( + &self, + request: Request, + ) -> Result, Status> { + let req = request.into_inner(); + let measurement = match AGENT + .lock() + .expect("Agent lock() failed.") + .get_cc_measurement(req.index, req.algo_id) + { + Ok(v) => v, + Err(e) => return Err(Status::internal(e.to_string())), + }; + + Ok(Response::new(GetCcMeasurementResponse { + measurement: Some(measurement), + })) + } + + async fn get_cc_eventlog( + &self, + request: Request, + ) -> Result, Status> { + let req = request.into_inner(); + let event_logs = match AGENT + .lock() + .expect("Agent lock() failed.") + .get_cc_eventlog(req.start, req.count) + { + Ok(v) => v, + Err(e) => return Err(Status::internal(e.to_string())), + }; + + Ok(Response::new(GetCcEventlogResponse { event_logs })) + } + + async fn get_cc_report( + &self, + request: Request, + ) -> Result, Status> { + let req = request.into_inner(); + let (cc_report, cc_type) = match AGENT + .lock() + .expect("Agent lock() failed.") + .get_cc_report(req.nonce, req.user_data) + { + Ok(v) => v, + Err(e) => return Err(Status::internal(e.to_string())), + }; + + Ok(Response::new(GetCcReportResponse { cc_report, cc_type })) + } +} diff --git a/service/eventlog-server/Makefile b/service/eventlog-server/Makefile deleted file mode 100644 index f4d24ba..0000000 --- a/service/eventlog-server/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2023, Intel Corporation. All rights reserved.
-# SPDX-License-Identifier: Apache-2.0 - -export GO111MODULE=on - -GOFILES := server - -all: clean - CGO_ENABLED=1 GOOS=linux GOARCH=amd64 - @go build -tags netgo -o ./eventlog-server ./server/server.go - -# The following is done this way as each patch on CI runs build and each merge runs deploy. So for build we don't need to build binary and hence -# no need to create a static binary with additional flags. However, for generating binary, additional build flags are necessary. This if used with -# mock plugin errors out for unit tests. So the seperation avoids the error. - -build: clean test cover -deploy: build - -.PHONY: test -test: clean - @go test -race ./... - -format: - @gofmt -s -w ${GOFILES} - -clean: - @find . -name "*so" -delete - @rm -f eventlog-server coverage.html coverage.out - -.PHONY: cover -cover: - @go test -race ./... -coverprofile=coverage.out - @go tool cover -html=coverage.out -o coverage.html diff --git a/service/eventlog-server/README.md b/service/eventlog-server/README.md deleted file mode 100644 index ea1f908..0000000 --- a/service/eventlog-server/README.md +++ /dev/null @@ -1,131 +0,0 @@ -# Service: CCNP Eventlog Server - -To further verify the integrity and authenticity of the measurements in the confidential cloud native environment and its underlying platform, event logs are absolutely needed. -By reviewing the event logs, user can identify any errors or issues that may be preventing the confidential environment from functioning correctly. - -This service (which is actually a GRPC server) will provide support to fetch the event logs for confidential cloud native environments, including TDX RTMR event logs and TPM event logs. - - - -## Introduction - -This service provides functionality to fetch event logs for confidential cloud native environments, both platform level(`PAAS` option) and container level (`SAAS` option). Using this service, user can fetch event logs for both TDX RTMR (`TDX_EVENTLOG` option) and TPM (`TPM_EVENTLOG` option). -Here shows the proto buf for the service: - -``` -enum CATEGORY { - TDX_EVENTLOG = 0; - TPM_EVENTLOG = 1; -} - -enum LEVEL { - PAAS = 0; - SAAS = 1; -} - -message GetEventlogRequest { - LEVEL eventlog_level = 1; - CATEGORY eventlog_category = 2; - int32 start_position = 3; - int32 count = 4; -} - -message GetEventlogReply { - string eventlog_data_loc = 1; -} - -service Eventlog { - rpc GetEventlog (GetEventlogRequest) returns (GetEventlogReply) {} -} -``` - -To select different level and category of event log, user shall send out request with different settings. -The service also supports fetching number of event logs start from a certain one. The `start_position` option and `count` option are provided for the usage. -User can find sample request in the Testing section. - -Request to the service will return the location of the collected event logs. They are stored under the folder `/run/ccnp-eventlog` by default. - - - -## Installation - -The Eventlog server service can be deployed as either DaemonSet or sidecar in different user scenarios within a kubernetes cluster. - - -### Prerequisite - -User need to have a kubernetes cluster ready to deploy the service. To simplify the deployment process, we provide Helm as one of the options for deployment. Please install Helm by following the [Helm official guide](https://helm.sh/docs/intro/install/). However, user can still install the service using the yaml file located in the manifests folder. - -### Build docker image - -The dockerfile for the service can be found under `container/ccnp-eventlog-server` directory. Use the following command to build the image: - -``` -cd ../.. -docker build -t ccnp-eventlog-server: -f container/ccnp-eventlog-server/Dockerfile . -``` -> Note: if you are using containerd as the default runtime for kubernetes. Please remember to use the following commands to import the image into containerd first: -``` -docker save -o ccnp-eventlog-server.tar ccnp-eventlog-server: -ctr -n=k8s.io image import ccnp-eventlog-server.tar -``` - -### Deploy as DaemonSet - -In the scenario of confidential kubernetes cluster, it is nice to deploy the Eventlog server service as a DaemonSet to serve all the applications living inside that cluster node. -Run the following command to deploy the service: - -``` -cd ../../deployment -helm install charts/eventlog-server --generate-name -``` -> Note: `ccnp` namespace may get duplicated in the case user installed multiple ccnp services. Please define the `namespaceCreate` option as `false` in the values.yaml before install the helm chart if certain case happens. - -User can also choose the manifests file to deploy the service: -``` -cd ../../deployment/manifests -kubectl create -f namespace.yaml -kubectl create -f eventlog-server-deployment.yaml -``` - -### Deploy as Sidecar - -In the scenario of confidential containers, it is nice to deploy the Eventlog server service as sidecar working along with the confidential containers. -The deployment helm chart and manifest file are still working in progress. - -### User application deployment - -Make sure that the user application mount the same event log directory into the container, which defined by `eventlogDir` variable within the helm chart values.yaml. -So that it can get the event log fetched and use according to their usage. - - - -## Testing - -User can play with service on host from the source code by following the steps below: - -1. Start the eventlog service - -``` -cd service/eventlog-server -make all - -./eventlog-server -``` - -2. Play with the service - -Use the `grpcurl` as the tool to play with the service. Please follow the [official documentation](https://github.com/fullstorydev/grpcurl) to install grpcurl - -Get all TDX RTMR event logs from the platform level: -``` -grpcurl -plaintext -d '{"eventlog_level": 0, "eventlog_category": 0}' -unix /run/ccnp/uds/eventlog.sock Eventlog/GetEventlog -``` - -Get 5 TDX RTMR event logs starting from the second one from platform level: -``` -grpcurl -plaintext -d '{"eventlog_level": 0, "eventlog_category": 0, "start_position": 2, "count": 5}' -unix /run/ccnp/uds/eventlog.sock Eventlog/GetEventlog -``` - -User can find the fetched event logs under the mounted directory. - diff --git a/service/eventlog-server/go.mod b/service/eventlog-server/go.mod deleted file mode 100644 index 667ddf8..0000000 --- a/service/eventlog-server/go.mod +++ /dev/null @@ -1,17 +0,0 @@ -module github.com/intel/confidential-cloud-native-primitives/service/eventlog-server - -go 1.20 - -require ( - github.com/golang/protobuf v1.5.3 - github.com/pkg/errors v0.9.1 - google.golang.org/grpc v1.56.3 -) - -require ( - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/protobuf v1.30.0 // indirect -) diff --git a/service/eventlog-server/go.sum b/service/eventlog-server/go.sum deleted file mode 100644 index a83618b..0000000 --- a/service/eventlog-server/go.sum +++ /dev/null @@ -1,22 +0,0 @@ -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/service/eventlog-server/proto/eventlog-server.pb.go b/service/eventlog-server/proto/eventlog-server.pb.go deleted file mode 100644 index 2c0d773..0000000 --- a/service/eventlog-server/proto/eventlog-server.pb.go +++ /dev/null @@ -1,208 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: proto/eventlog-server.proto - -package getEventlog - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type CATEGORY int32 - -const ( - CATEGORY_TDX_EVENTLOG CATEGORY = 0 - CATEGORY_TPM_EVENTLOG CATEGORY = 1 -) - -var CATEGORY_name = map[int32]string{ - 0: "TDX_EVENTLOG", - 1: "TPM_EVENTLOG", -} - -var CATEGORY_value = map[string]int32{ - "TDX_EVENTLOG": 0, - "TPM_EVENTLOG": 1, -} - -func (x CATEGORY) String() string { - return proto.EnumName(CATEGORY_name, int32(x)) -} - -func (CATEGORY) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_3d123471d781508e, []int{0} -} - -type LEVEL int32 - -const ( - LEVEL_PAAS LEVEL = 0 - LEVEL_SAAS LEVEL = 1 -) - -var LEVEL_name = map[int32]string{ - 0: "PAAS", - 1: "SAAS", -} - -var LEVEL_value = map[string]int32{ - "PAAS": 0, - "SAAS": 1, -} - -func (x LEVEL) String() string { - return proto.EnumName(LEVEL_name, int32(x)) -} - -func (LEVEL) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_3d123471d781508e, []int{1} -} - -type GetEventlogRequest struct { - EventlogLevel LEVEL `protobuf:"varint,1,opt,name=eventlog_level,json=eventlogLevel,proto3,enum=LEVEL" json:"eventlog_level,omitempty"` - EventlogCategory CATEGORY `protobuf:"varint,2,opt,name=eventlog_category,json=eventlogCategory,proto3,enum=CATEGORY" json:"eventlog_category,omitempty"` - StartPosition int32 `protobuf:"varint,3,opt,name=start_position,json=startPosition,proto3" json:"start_position,omitempty"` - Count int32 `protobuf:"varint,4,opt,name=count,proto3" json:"count,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetEventlogRequest) Reset() { *m = GetEventlogRequest{} } -func (m *GetEventlogRequest) String() string { return proto.CompactTextString(m) } -func (*GetEventlogRequest) ProtoMessage() {} -func (*GetEventlogRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_3d123471d781508e, []int{0} -} - -func (m *GetEventlogRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetEventlogRequest.Unmarshal(m, b) -} -func (m *GetEventlogRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetEventlogRequest.Marshal(b, m, deterministic) -} -func (m *GetEventlogRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetEventlogRequest.Merge(m, src) -} -func (m *GetEventlogRequest) XXX_Size() int { - return xxx_messageInfo_GetEventlogRequest.Size(m) -} -func (m *GetEventlogRequest) XXX_DiscardUnknown() { - xxx_messageInfo_GetEventlogRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_GetEventlogRequest proto.InternalMessageInfo - -func (m *GetEventlogRequest) GetEventlogLevel() LEVEL { - if m != nil { - return m.EventlogLevel - } - return LEVEL_PAAS -} - -func (m *GetEventlogRequest) GetEventlogCategory() CATEGORY { - if m != nil { - return m.EventlogCategory - } - return CATEGORY_TDX_EVENTLOG -} - -func (m *GetEventlogRequest) GetStartPosition() int32 { - if m != nil { - return m.StartPosition - } - return 0 -} - -func (m *GetEventlogRequest) GetCount() int32 { - if m != nil { - return m.Count - } - return 0 -} - -type GetEventlogReply struct { - EventlogDataLoc string `protobuf:"bytes,1,opt,name=eventlog_data_loc,json=eventlogDataLoc,proto3" json:"eventlog_data_loc,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetEventlogReply) Reset() { *m = GetEventlogReply{} } -func (m *GetEventlogReply) String() string { return proto.CompactTextString(m) } -func (*GetEventlogReply) ProtoMessage() {} -func (*GetEventlogReply) Descriptor() ([]byte, []int) { - return fileDescriptor_3d123471d781508e, []int{1} -} - -func (m *GetEventlogReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetEventlogReply.Unmarshal(m, b) -} -func (m *GetEventlogReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetEventlogReply.Marshal(b, m, deterministic) -} -func (m *GetEventlogReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetEventlogReply.Merge(m, src) -} -func (m *GetEventlogReply) XXX_Size() int { - return xxx_messageInfo_GetEventlogReply.Size(m) -} -func (m *GetEventlogReply) XXX_DiscardUnknown() { - xxx_messageInfo_GetEventlogReply.DiscardUnknown(m) -} - -var xxx_messageInfo_GetEventlogReply proto.InternalMessageInfo - -func (m *GetEventlogReply) GetEventlogDataLoc() string { - if m != nil { - return m.EventlogDataLoc - } - return "" -} - -func init() { - proto.RegisterEnum("CATEGORY", CATEGORY_name, CATEGORY_value) - proto.RegisterEnum("LEVEL", LEVEL_name, LEVEL_value) - proto.RegisterType((*GetEventlogRequest)(nil), "GetEventlogRequest") - proto.RegisterType((*GetEventlogReply)(nil), "GetEventlogReply") -} - -func init() { proto.RegisterFile("proto/eventlog-server.proto", fileDescriptor_3d123471d781508e) } - -var fileDescriptor_3d123471d781508e = []byte{ - // 350 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x91, 0x51, 0x6b, 0xf2, 0x30, - 0x14, 0x86, 0xed, 0xf7, 0xa9, 0x68, 0x36, 0x5d, 0xcd, 0x76, 0x51, 0xe6, 0x8d, 0x08, 0x03, 0x11, - 0xda, 0x82, 0x83, 0xed, 0x6e, 0xe0, 0xb4, 0x78, 0xd3, 0x4d, 0xa9, 0x22, 0xdb, 0x6e, 0x4a, 0x8c, - 0x59, 0x17, 0x88, 0x4d, 0xd7, 0x9e, 0x16, 0xfc, 0x67, 0xfb, 0x79, 0xa3, 0xd1, 0x4e, 0xe7, 0xee, - 0x4e, 0x9f, 0xf7, 0x2d, 0x79, 0x92, 0x83, 0xda, 0x51, 0x2c, 0x41, 0xda, 0x2c, 0x63, 0x21, 0x08, - 0x19, 0x98, 0x09, 0x8b, 0x33, 0x16, 0x5b, 0x8a, 0x76, 0xbf, 0x34, 0x84, 0x27, 0x0c, 0x9c, 0x7d, - 0xe8, 0xb1, 0xcf, 0x94, 0x25, 0x80, 0x4d, 0xd4, 0x2c, 0xfa, 0xbe, 0x60, 0x19, 0x13, 0x86, 0xd6, - 0xd1, 0x7a, 0xcd, 0x41, 0xd5, 0x72, 0x9d, 0xa5, 0xe3, 0x7a, 0x8d, 0x22, 0x75, 0xf3, 0x10, 0xdf, - 0xa1, 0xd6, 0x4f, 0x9d, 0x12, 0x60, 0x81, 0x8c, 0xb7, 0xc6, 0x3f, 0xf5, 0x47, 0xdd, 0x1a, 0x0d, - 0x17, 0xce, 0x64, 0xea, 0xbd, 0x7a, 0x7a, 0xd1, 0x19, 0xed, 0x2b, 0xf8, 0x06, 0x35, 0x13, 0x20, - 0x31, 0xf8, 0x91, 0x4c, 0x38, 0x70, 0x19, 0x1a, 0xff, 0x3b, 0x5a, 0xaf, 0xe2, 0x35, 0x14, 0x9d, - 0xed, 0x21, 0xbe, 0x42, 0x15, 0x2a, 0xd3, 0x10, 0x8c, 0xb2, 0x4a, 0x77, 0x1f, 0xdd, 0x07, 0xa4, - 0xff, 0x32, 0x8f, 0xc4, 0x16, 0xf7, 0x8f, 0x44, 0xd6, 0x04, 0x88, 0x2f, 0x24, 0x55, 0xea, 0x75, - 0xef, 0xa2, 0x08, 0xc6, 0x04, 0x88, 0x2b, 0x69, 0xdf, 0x42, 0xb5, 0x42, 0x0d, 0xeb, 0xe8, 0x7c, - 0x31, 0x7e, 0xf1, 0x9d, 0xa5, 0xf3, 0xbc, 0x70, 0xa7, 0x13, 0xbd, 0xa4, 0xc8, 0xec, 0xe9, 0x40, - 0xb4, 0x7e, 0x1b, 0x55, 0xd4, 0xe5, 0x71, 0x0d, 0x95, 0x67, 0xc3, 0xe1, 0x5c, 0x2f, 0xe5, 0xd3, - 0x3c, 0x9f, 0xb4, 0xc1, 0x08, 0xd5, 0x0a, 0x13, 0x7c, 0x8f, 0xce, 0x8e, 0xc4, 0xf0, 0xa5, 0xf5, - 0xf7, 0x81, 0xaf, 0x5b, 0xd6, 0xa9, 0x7b, 0xb7, 0xf4, 0x48, 0xde, 0xfc, 0x80, 0xc3, 0x47, 0xba, - 0xb2, 0xa8, 0xdc, 0xd8, 0x3c, 0x04, 0x26, 0x6c, 0x2a, 0xc3, 0x77, 0xbe, 0x66, 0x21, 0x70, 0x22, - 0x4c, 0x2a, 0x64, 0xba, 0x36, 0x43, 0x02, 0x3c, 0x63, 0x66, 0x14, 0xf3, 0x0d, 0xcf, 0xa7, 0xc4, - 0xce, 0x57, 0xca, 0x29, 0x3b, 0xdd, 0xb1, 0xbd, 0xdb, 0x7c, 0x70, 0x38, 0x69, 0x55, 0x55, 0xe8, - 0xf6, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x51, 0xe1, 0x30, 0x36, 0x15, 0x02, 0x00, 0x00, -} diff --git a/service/eventlog-server/proto/eventlog-server.proto b/service/eventlog-server/proto/eventlog-server.proto deleted file mode 120000 index cfee887..0000000 --- a/service/eventlog-server/proto/eventlog-server.proto +++ /dev/null @@ -1 +0,0 @@ -../../../api/eventlog-server.proto \ No newline at end of file diff --git a/service/eventlog-server/proto/eventlog-server_grpc.pb.go b/service/eventlog-server/proto/eventlog-server_grpc.pb.go deleted file mode 100644 index fa97032..0000000 --- a/service/eventlog-server/proto/eventlog-server_grpc.pb.go +++ /dev/null @@ -1,105 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.11.4 -// source: proto/eventlog-server.proto - -package getEventlog - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// EventlogClient is the client API for Eventlog service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type EventlogClient interface { - GetEventlog(ctx context.Context, in *GetEventlogRequest, opts ...grpc.CallOption) (*GetEventlogReply, error) -} - -type eventlogClient struct { - cc grpc.ClientConnInterface -} - -func NewEventlogClient(cc grpc.ClientConnInterface) EventlogClient { - return &eventlogClient{cc} -} - -func (c *eventlogClient) GetEventlog(ctx context.Context, in *GetEventlogRequest, opts ...grpc.CallOption) (*GetEventlogReply, error) { - out := new(GetEventlogReply) - err := c.cc.Invoke(ctx, "/Eventlog/GetEventlog", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// EventlogServer is the server API for Eventlog service. -// All implementations must embed UnimplementedEventlogServer -// for forward compatibility -type EventlogServer interface { - GetEventlog(context.Context, *GetEventlogRequest) (*GetEventlogReply, error) - mustEmbedUnimplementedEventlogServer() -} - -// UnimplementedEventlogServer must be embedded to have forward compatible implementations. -type UnimplementedEventlogServer struct { -} - -func (UnimplementedEventlogServer) GetEventlog(context.Context, *GetEventlogRequest) (*GetEventlogReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetEventlog not implemented") -} -func (UnimplementedEventlogServer) mustEmbedUnimplementedEventlogServer() {} - -// UnsafeEventlogServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to EventlogServer will -// result in compilation errors. -type UnsafeEventlogServer interface { - mustEmbedUnimplementedEventlogServer() -} - -func RegisterEventlogServer(s grpc.ServiceRegistrar, srv EventlogServer) { - s.RegisterService(&Eventlog_ServiceDesc, srv) -} - -func _Eventlog_GetEventlog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetEventlogRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(EventlogServer).GetEventlog(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/Eventlog/GetEventlog", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(EventlogServer).GetEventlog(ctx, req.(*GetEventlogRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// Eventlog_ServiceDesc is the grpc.ServiceDesc for Eventlog service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Eventlog_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "Eventlog", - HandlerType: (*EventlogServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetEventlog", - Handler: _Eventlog_GetEventlog_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "proto/eventlog-server.proto", -} diff --git a/service/eventlog-server/resources/tdx.go b/service/eventlog-server/resources/tdx.go deleted file mode 100644 index ba643d0..0000000 --- a/service/eventlog-server/resources/tdx.go +++ /dev/null @@ -1,406 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "bytes" - "encoding/binary" - "encoding/json" - "fmt" - "io" - "log" - "os" - - pkgerrors "github.com/pkg/errors" -) - -const ( - //The location of CCEL table - CCEL_FILE_LOCATION = "/sys/firmware/acpi/tables/CCEL" - CCEL_DATA_LOCATION = "/sys/firmware/acpi/tables/data/CCEL" - //The location of mounted CCEL table - CCEL_FILE_MOUNT_LOCATION = "/run/firmware/acpi/tables/CCEL" - CCEL_DATA_MOUNT_LOCATION = "/run/firmware/acpi/tables/data/CCEL" - - EVENT_TYPE_EV_NO_ACTION = 0x3 -) - -var ( - TdxGetEventlogErr = pkgerrors.New("Failed to get eventlog in CCEL table.") - CcelTableNotFoundErr = pkgerrors.New("CCEL table not found.") - InvalidCcelTableErr = pkgerrors.New("CCEL table with invalid data") - FetchCcelTableAttrErr = pkgerrors.New("Failed to get the base address of CCEL table") -) - -func GetTdxEventlog(start_position int, count int) (string, error) { - - var eventlog string - var object *os.File - var err error - - /* Check if the ccel file exists*/ - if _, err = os.Stat(CCEL_FILE_MOUNT_LOCATION); err != nil { - log.Println("Checking CCEL file in host path") - if _, err = os.Stat(CCEL_FILE_LOCATION); err != nil { - return "", err - } - } - - /* Open ccel file to get prepared for event log fetching*/ - object, err = os.OpenFile(CCEL_FILE_MOUNT_LOCATION, os.O_RDONLY, 0644) - if err != nil { - object, err = os.OpenFile(CCEL_FILE_LOCATION, os.O_RDONLY, 0644) - if err != nil { - return "", CcelTableNotFoundErr - } - } - - data, err := io.ReadAll(object) - if err != nil { - return "", err - } - - if len(data) == 0 || !bytes.Equal(data[0:4], []byte("CCEL")) { - return "", InvalidCcelTableErr - } - - eventlog, err = parseTdxEventlog(data, start_position, count) - if err != nil { - return "", err - } - - return eventlog, nil -} - -func parseTdxEventlog(data []byte, position int, count int) (string, error) { - - var baseAddr, currLen uint64 - var num int - var eventlogs TDEventLogs - - if len(data) > 56 { - return "", InvalidCcelTableErr - } - - err := binary.Read(bytes.NewReader(data[48:56]), binary.LittleEndian, &baseAddr) - if err != nil { - return "", FetchCcelTableAttrErr - } - - err = binary.Read(bytes.NewReader(data[40:48]), binary.LittleEndian, &currLen) - if err != nil { - return "", FetchCcelTableAttrErr - } - - eventlogs, num, err = fetchEventlogs() - if err != nil { - return "", err - } - - if position+count >= num { - return "", pkgerrors.New("Invalid count exceeds event log length") - } - - if count != 0 { - eventlogs = TDEventLogs{ - Header: eventlogs.Header, - EventLogs: eventlogs.EventLogs[position : position+count], - } - } - - eventlogs_str, err := json.Marshal(eventlogs) - if err != nil { - log.Println("Error in marshaling event logs") - return "", err - } - return string(eventlogs_str), nil -} - -func fetchEventlogs() (TDEventLogs, int, error) { - - var index int - var object *os.File - var err error - - /* Check if the ccel file exists in either host or container*/ - if _, err = os.Stat(CCEL_DATA_MOUNT_LOCATION); err != nil { - log.Println("Checking CCEL data in host path") - _, err = os.Stat(CCEL_DATA_LOCATION) - if err != nil { - return TDEventLogs{}, 0, err - } - } - - /* Open ccel data file to get prepared for event log fetching*/ - object, err = os.OpenFile(CCEL_DATA_MOUNT_LOCATION, os.O_RDONLY, 0644) - if err != nil { - object, err = os.OpenFile(CCEL_DATA_LOCATION, os.O_RDONLY, 0644) - if err != nil { - return TDEventLogs{}, 0, CcelTableNotFoundErr - } - } - - data, err := io.ReadAll(object) - if err != nil { - return TDEventLogs{}, 0, err - } - - if len(data) == 0 { - return TDEventLogs{}, 0, CcelTableNotFoundErr - } - - eventLogs := TDEventLogs{} - specidHeader := TDEventLogSpecIdHeader{} - index = 0 - count := 0 - - for index < len(data) { - var rtmr, etype uint32 - start := index - - rtmr, index, err = getUint32Object(data, index) - if err != nil { - log.Println("Error in getting RTMR value") - return TDEventLogs{}, 0, err - } - - if rtmr == 0xFFFFFFFF { - break - } - - etype, _, err = getUint32Object(data, index) - if err != nil { - log.Println("Error in getting event type") - return TDEventLogs{}, 0, err - } - - if etype == EVENT_TYPE_EV_NO_ACTION { - - specidHeader.Rtmr, specidHeader.Etype, specidHeader.DigestCount, index, err = getBasicInfo(data[start:]) - if err != nil { - log.Println("Error in getting basic info") - return TDEventLogs{}, 0, err - } - - index += 20 - index += 24 - - specidHeader.DigestSizes, index, err = getHeaderDigestInfo(data[start:], index) - if err != nil { - log.Println("Error in getting header digest info") - return TDEventLogs{}, 0, err - } - - var vendorSize uint8 - vendorSize, index, err = getUint8Object(data[start:], index) - if err != nil { - log.Println("Error in getting vendor size") - return TDEventLogs{}, 0, err - } - - index = index + int(vendorSize) - specidHeader.Length = int(index) - specidHeader.HeaderData = data[0:index] - eventLogs.Header = specidHeader - - index = start + specidHeader.Length - count += 1 - continue - - } - - eventLog := TDEventLog{} - eventLog.Rtmr, eventLog.Etype, eventLog.DigestCount, index, err = getBasicInfo(data[start:]) - if err != nil { - log.Println("Error in getting basic info") - return TDEventLogs{}, 0, err - } - - eventLog.Digests, eventLog.AlgorithmId, index, err = getEventLogDigestInfo(data[start:], index, eventLog.DigestCount, eventLogs.Header.DigestSizes) - if err != nil { - log.Println("Error in getting event log digest info") - return TDEventLogs{}, 0, err - } - - eventLog.EventSize, index, err = getUint32Object(data[start:], index) - if err != nil { - log.Println("Error in getting event size") - return TDEventLogs{}, 0, err - } - - eventLog.Event = data[int(start)+index : int(start)+index+int(eventLog.EventSize)] - index = index + int(eventLog.EventSize) - eventLog.Length = index - eventLog.Data = data[start : start+index] - eventLogs.EventLogs = append(eventLogs.EventLogs, eventLog) - index = start + eventLog.Length - - count += 1 - } - - return eventLogs, count, nil -} - -type TDEventLogSpecIdHeader struct { - Address uint64 - Length int - HeaderData []byte - Rtmr uint32 - Etype uint32 - DigestCount uint32 - DigestSizes map[uint16]uint16 -} - -type TDEventLog struct { - Rtmr uint32 - Etype uint32 - DigestCount uint32 - Digests []string - Data []byte - Event []byte - Length int - EventSize uint32 - AlgorithmId uint16 -} - -type TDEventLogs struct { - Header TDEventLogSpecIdHeader - EventLogs []TDEventLog -} - -func getBasicInfo(data []byte) (uint32, uint32, uint32, int, error) { - - var rtmr, etype, digestCount uint32 - var err error - i := 0 - - rtmr, i, err = getUint32Object(data, i) - if err != nil { - log.Println("Error in getting RTMR") - return uint32(0), uint32(0), uint32(0), 0, err - } - - etype, i, err = getUint32Object(data, i) - if err != nil { - log.Println("Error in getting event log type") - return uint32(0), uint32(0), uint32(0), 0, err - } - - digestCount, i, err = getUint32Object(data, i) - if err != nil { - log.Println("Error in getting digest count") - return uint32(0), uint32(0), uint32(0), 0, err - } - - return rtmr - 1, etype, digestCount, i, nil -} - -func getHeaderDigestInfo(data []byte, index int) (map[uint16]uint16, int, error) { - - var algNum uint32 - var algId, digestSize uint16 - var err error - - digestSizes := make(map[uint16]uint16) - i := index - - algNum, i, err = getUint32Object(data, i) - if err != nil { - log.Println("Error in getting algorithm number") - return digestSizes, 0, err - } - - for j := 0; j < int(algNum); j++ { - algId, i, err = getUint16Object(data, i) - if err != nil { - log.Println("Error in getting algorithm id") - return digestSizes, 0, err - } - - digestSize, i, err = getUint16Object(data, i) - if err != nil { - log.Println("Error in getting algorithm digest size") - return digestSizes, 0, err - } - - digestSizes[algId] = digestSize - } - - return digestSizes, i, nil -} - -func getEventLogDigestInfo(data []byte, index int, digestCount uint32, digestSizes map[uint16]uint16) ([]string, uint16, int, error) { - - var algId uint16 - var err error - var digests []string - - i := index - - for j := 0; j < int(digestCount); j++ { - algId, i, err = getUint16Object(data, i) - if err != nil { - log.Println("Error in getting algorithm id") - return digests, uint16(0), 0, err - } - - for k := range digestSizes { - if k == algId { - digestSize := digestSizes[k] - digestData := data[i : i+int(digestSize)] - i = i + int(digestSize) - digests = append(digests, fmt.Sprintf("%v", digestData)) - } - } - } - - return digests, algId, i, nil -} - -func getUint32Object(data []byte, index int) (uint32, int, error) { - var value uint32 - - if index+4 > len(data) { - return uint32(0), index, pkgerrors.New("Exceed valid length") - } - err := binary.Read(bytes.NewReader(data[index:index+4]), binary.LittleEndian, &value) - if err != nil { - log.Println("Error in reading uint32 object") - return uint32(0), index, err - } - - return value, index + 4, nil -} - -func getUint16Object(data []byte, index int) (uint16, int, error) { - var value uint16 - - if index+2 > len(data) { - return uint16(0), index, pkgerrors.New("Exceed valid length") - } - err := binary.Read(bytes.NewReader(data[index:index+2]), binary.LittleEndian, &value) - if err != nil { - log.Println("Error in reading uint16 object") - return uint16(0), index, err - } - - return value, index + 2, nil -} - -func getUint8Object(data []byte, index int) (uint8, int, error) { - var value uint8 - - if index+1 > len(data) { - return uint8(0), index, pkgerrors.New("Exceed valid length") - } - err := binary.Read(bytes.NewReader(data[index:index+1]), binary.LittleEndian, &value) - if err != nil { - log.Println("Error in reading uint8 object") - return uint8(0), index, err - } - - return value, index + 1, nil -} diff --git a/service/eventlog-server/resources/tdx_test.go b/service/eventlog-server/resources/tdx_test.go deleted file mode 100644 index d18c2d2..0000000 --- a/service/eventlog-server/resources/tdx_test.go +++ /dev/null @@ -1,150 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - pkgerrors "github.com/pkg/errors" - "testing" -) - -const ( - ERR_MSG = "Exceed valid length" -) - -func TestGetUintObjectInvalidLength(t *testing.T) { - data := make([]byte, 0) - index := 0 - var err error - var value1 uint32 - var value2 uint16 - var value3 uint8 - - value1, index, err = getUint32Object(data, index) - if err.Error() != ERR_MSG || value1 != uint32(0) || index != 0 { - t.Fatalf(`getUint32Object([], 0) = %d, %d, %v want match for %d, %d, %v`, - value1, index, err, uint32(0), 0, pkgerrors.New("Exceed valid length")) - } - - value2, index, err = getUint16Object(data, index) - if err.Error() != ERR_MSG || value2 != uint16(0) || index != 0 { - t.Fatalf(`getUint16Object([], 0) = %d, %d, %v want match for %d, %d, %v`, - value2, index, err, uint16(0), 0, pkgerrors.New("Exceed valid length")) - } - - value3, index, err = getUint8Object(data, index) - if err.Error() != ERR_MSG || value3 != uint8(0) || index != 0 { - t.Fatalf(`getUint8Object([], 0) = %d, %d, %v want match for %d, %d, %v`, - value3, index, err, uint8(0), 0, pkgerrors.New("Exceed valid length")) - } -} - -func TestGetUintObjectValidLength(t *testing.T) { - data := make([]byte, 8) - index := 0 - var err error - var value1 uint32 - var value2 uint16 - var value3 uint8 - - value1, index, err = getUint32Object(data, index) - if err != nil || value1 != uint32(0) || index != 4 { - t.Fatalf(`getUint32Object([], 0) = %d, %d, %v want match for %d, %d, %v`, - value1, index, err, uint32(0), 4, nil) - } - - value2, index, err = getUint16Object(data, index) - if err != nil || value2 != uint16(0) || index != 6 { - t.Fatalf(`getUint16Object([], 0) = %d, %d, %v want match for %d, %d, %v`, - value2, index, err, uint16(0), 6, nil) - } - - value3, index, err = getUint8Object(data, index) - if err != nil || value3 != uint8(0) || index != 7 { - t.Fatalf(`getUint8Object([], 0) = %d, %d, %v want match for %d, %d, %v`, - value3, index, err, uint8(0), 7, nil) - } -} - -func TestGetEventLogDigestInfo(t *testing.T) { - var flag bool - - digestCount := uint32(1) - data := make([]byte, 5) - index := 0 - digestSizes := make(map[uint16]uint16) - digestSizes[uint16(0)] = 1 - flag = true - - digests, algId, index, err := getEventLogDigestInfo(data, index, digestCount, digestSizes) - if len(digests) != 1 { - flag = false - } - - for _, item := range digests { - if item != "0" { - flag = false - break - } - } - - if err != nil || flag || algId != uint16(0) || index != 3 { - t.Fatalf(`getEventLogDigestInfo([0,0,0,0,0], 0, 1, map[0]=1) = %s, %d, %d, %v want match for %s, %d, %d, %v`, - digests, algId, index, err, []string{"0"}, uint16(0), 3, nil) - } -} - -func TestGetHeaderDigestInfo(t *testing.T) { - data := make([]byte, 8) - index := 0 - - // Success - data[0] = uint8(1) - data[6] = uint8(48) - - digestsizes, index, err := getHeaderDigestInfo(data, index) - if err != nil || digestsizes[0] != uint16(48) || index != 8 { - t.Fatalf(`getHeaderDigestInfo([1,0,0,0,0,0,48,0], 0) = %d, %d, %v want match for %d, %d, %v`, - digestsizes[0], index, err, uint16(48), 8, nil) - } - - // Failure - data[0] = uint8(0) - data[1] = uint8(1) - - digestsizes, index, err = getHeaderDigestInfo(data, index) - if err.Error() != ERR_MSG || digestsizes[0] != uint16(0) || index != 0 { - t.Fatalf(`getHeaderDigestInfo([0,1,0,0,0,0,48,0], 0) = %d, %d, %v want match for %d, %d, %v`, - digestsizes[0], index, err, uint16(0), 0, ERR_MSG) - } -} - -func TestGetBasicInfo(t *testing.T) { - data := make([]byte, 12) - data[0] = uint8(1) - - rtmr, etype, digestCount, index, err := getBasicInfo(data) - if err != nil || index != 12 || etype != uint32(0) || digestCount != uint32(0) { - t.Fatalf(`getBasicInfo([1,0,0,0,0,0,0,0,0,0,0,0]) = %d, %d, %d, %d, %v want %d, %d, %d, %d, %v`, - rtmr, etype, digestCount, index, err, uint32(0), uint32(0), uint32(0), uint32(0), nil) - } -} - -func TestFetchEventlog(t *testing.T) { - _, count, err := fetchEventlogs() - if err != nil || count == 0 { - t.Fatalf(`fetchEventlog() = %d, %v want %s, %v`, count, err, "large then 0", nil) - } -} - -func TestGetTdxEventlog(t *testing.T) { - start_position := 0 - count := 1 - - log, err := GetTdxEventlog(start_position, count) - if err != nil || log == "" { - t.Fatalf(`GetTdxEventlog(0, 1) = %s, %v want %s, %v`, log, err, "eventlogs exist", nil) - } -} diff --git a/service/eventlog-server/resources/tpm.go b/service/eventlog-server/resources/tpm.go deleted file mode 100644 index 8394982..0000000 --- a/service/eventlog-server/resources/tpm.go +++ /dev/null @@ -1,66 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "io" - "log" - "os" - - pkgerrors "github.com/pkg/errors" -) - -const ( - //The location of CCEL table - TPM_EVENT_LOG_LOCATION = "/sys/kernel/security/tpm0/binary_bios_measurements" - - CHUNK_SIZE = 16384 -) - -var ( - TpmGetEventlogErr = pkgerrors.New("Failed to get eventlog in TPM.") - TpmEventlogNotFoundErr = pkgerrors.New("TPM eventlog not found.") -) - -func GetTpmEventlog(start_position int, length int) (string, error) { - - var eventlog string - - /* Check if the tpm eventlog file exists*/ - if _, err := os.Stat(TPM_EVENT_LOG_LOCATION); err != nil { - return "", err - } - - /* Read eventlog data*/ - object, err := os.OpenFile(TPM_EVENT_LOG_LOCATION, os.O_RDONLY, 0644) - if err != nil { - return "", TpmEventlogNotFoundErr - } - - data, err := io.ReadAll(object) - if err != nil { - return "", err - } - - if len(data) == 0 { - return "", TpmEventlogNotFoundErr - } - - eventlog, err = parseTpmEventlog(data, start_position, length) - if err != nil { - return "", err - } - - return eventlog, nil -} - -func parseTpmEventlog(data []byte, position int, length int) (string, error) { - //not implemented, refer to https://github.com/tpm2-software/tpm2-tools/blob/master/tools/misc/tpm2_eventlog.c#L62 - log.Println("Not implemented.") - - return "", nil - -} diff --git a/service/eventlog-server/resources/tpm_test.go b/service/eventlog-server/resources/tpm_test.go deleted file mode 100644 index 98fb33d..0000000 --- a/service/eventlog-server/resources/tpm_test.go +++ /dev/null @@ -1,24 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "testing" -) - -const ( - TPM_ERR_MSG = "stat /sys/kernel/security/tpm0/binary_bios_measurements: no such file or directory" -) - -func TestGetTpmEventlog(t *testing.T) { - start_position := 0 - count := 1 - - _, err := GetTpmEventlog(start_position, count) - if err.Error() != TPM_ERR_MSG { - t.Fatalf(`GetTpmEventlog(0,1) get error %s want %s`, err.Error(), TPM_ERR_MSG) - } -} diff --git a/service/eventlog-server/server/server.go b/service/eventlog-server/server/server.go deleted file mode 100644 index ee41a42..0000000 --- a/service/eventlog-server/server/server.go +++ /dev/null @@ -1,151 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package main - -import ( - "context" - "fmt" - "log" - "net" - "os" - - "google.golang.org/grpc" - "google.golang.org/grpc/health" - "google.golang.org/grpc/health/grpc_health_v1" - "google.golang.org/grpc/reflection" - - pb "github.com/intel/confidential-cloud-native-primitives/service/eventlog-server/proto" - resources "github.com/intel/confidential-cloud-native-primitives/service/eventlog-server/resources" - pkgerrors "github.com/pkg/errors" -) - -var ( - InvalidRequestErr = pkgerrors.New("Invalid Request") -) - -const ( - RUNTIME_EVENT_LOG_DIR = "/run/ccnp-eventlog/" - FILENAME = "eventlog.log" - protocol = "unix" - sockAddr = "/run/ccnp/uds/eventlog.sock" - MAX_CONCURRENT_STREAMS = 100 -) - -type eventlogServer struct { - pb.UnimplementedEventlogServer -} - -func getContainerLevelEventlog(eventlogReq *pb.GetEventlogRequest) (string, error) { - // not implemented - return "", nil -} - -func getPaasLevelEventlog(eventlogReq *pb.GetEventlogRequest) (string, error) { - var category pb.CATEGORY - var eventlog string - var err error - - category = eventlogReq.EventlogCategory - - switch category { - case pb.CATEGORY_TPM_EVENTLOG: - eventlog, err = resources.GetTpmEventlog(int(eventlogReq.StartPosition), int(eventlogReq.Count)) - case pb.CATEGORY_TDX_EVENTLOG: - eventlog, err = resources.GetTdxEventlog(int(eventlogReq.StartPosition), int(eventlogReq.Count)) - default: - log.Println("Invalid eventlog category.") - return "", InvalidRequestErr - } - return eventlog, err -} - -func (*eventlogServer) GetEventlog(ctx context.Context, eventlogReq *pb.GetEventlogRequest) (*pb.GetEventlogReply, error) { - var eventlog_level pb.LEVEL - var eventlog string - var err error - - eventlog_level = eventlogReq.EventlogLevel - - switch eventlog_level { - case pb.LEVEL_SAAS: - eventlog, err = getContainerLevelEventlog(eventlogReq) - case pb.LEVEL_PAAS: - eventlog, err = getPaasLevelEventlog(eventlogReq) - default: - log.Println("Invalid eventlog level.") - return &pb.GetEventlogReply{}, InvalidRequestErr - } - - if err != nil { - return &pb.GetEventlogReply{}, err - } - - if _, err := os.Stat(RUNTIME_EVENT_LOG_DIR); os.IsNotExist(err) { - err := os.MkdirAll(RUNTIME_EVENT_LOG_DIR, os.ModePerm) - if err != nil { - return &pb.GetEventlogReply{}, err - } - } - - file, err := os.Create(fmt.Sprintf("%s%s", RUNTIME_EVENT_LOG_DIR, FILENAME)) - if err != nil { - log.Println("Error creating event log file in", RUNTIME_EVENT_LOG_DIR) - return &pb.GetEventlogReply{}, err - } - defer file.Close() - - _, err = file.WriteString(eventlog) - if err != nil { - log.Println("Error writing event log file in", RUNTIME_EVENT_LOG_DIR+FILENAME) - return &pb.GetEventlogReply{}, err - } - - return &pb.GetEventlogReply{EventlogDataLoc: RUNTIME_EVENT_LOG_DIR + FILENAME}, nil -} - -func (*eventlogServer) Check(ctx context.Context, in *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) { - return &grpc_health_v1.HealthCheckResponse{ - Status: grpc_health_v1.HealthCheckResponse_SERVING, - }, nil -} - -func (*eventlogServer) Watch(in *grpc_health_v1.HealthCheckRequest, stream grpc_health_v1.Health_WatchServer) error { - return nil -} - -func newServer() *eventlogServer { - s := &eventlogServer{} - return s -} - -func main() { - if _, err := os.Stat(sockAddr); !os.IsNotExist(err) { - if err := os.RemoveAll(sockAddr); err != nil { - log.Fatal(err) - } - } - - lis, err := net.Listen(protocol, sockAddr) - if err != nil { - log.Fatalf("failed to listen: %v", err) - } - - opts := []grpc.ServerOption{ - grpc.MaxConcurrentStreams(MAX_CONCURRENT_STREAMS), - } - - grpcServer := grpc.NewServer(opts...) - healthServer := health.NewServer() - - pb.RegisterEventlogServer(grpcServer, newServer()) - grpc_health_v1.RegisterHealthServer(grpcServer, healthServer) - - log.Printf("server listening at %v", lis.Addr()) - reflection.Register(grpcServer) - if err = grpcServer.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) - } -} diff --git a/service/eventlog-server/server/server_test.go b/service/eventlog-server/server/server_test.go deleted file mode 100644 index 311bd34..0000000 --- a/service/eventlog-server/server/server_test.go +++ /dev/null @@ -1,173 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ -package main - -import ( - "context" - "errors" - "log" - "net" - "testing" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/test/bufconn" - - pb "github.com/intel/confidential-cloud-native-primitives/service/eventlog-server/proto" -) - -const ( - INVALID_EVENTLOG_LEVEL pb.LEVEL = 9 - INVALID_EVENTLOG_CATEGORY pb.CATEGORY = 9 -) - -var lis *bufconn.Listener - -func initTestServer(ctx context.Context) { - buffer := 1024 * 1024 - lis = bufconn.Listen(buffer) - - server := grpc.NewServer() - pb.RegisterEventlogServer(server, &eventlogServer{}) - go func() { - if err := server.Serve(lis); err != nil { - log.Printf("error serving server: %v", err) - } - }() -} - -func TestEventlogServerGetEventlog(t *testing.T) { - ctx := context.Background() - initTestServer(ctx) - - conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer( - func(context.Context, string) (net.Conn, error) { - return lis.Dial() - }), grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - log.Printf("failed to connect to server: %v", err) - return - } - defer conn.Close() - client := pb.NewEventlogClient(conn) - - type expectation struct { - out *pb.GetEventlogReply - err error - } - - tests := map[string]struct { - in *pb.GetEventlogRequest - expected expectation - }{ - "Empty_Request": { - in: &pb.GetEventlogRequest{}, - expected: expectation{ - out: &pb.GetEventlogReply{ - EventlogDataLoc: "/run/ccnp-eventlog/eventlog.log", - }, - err: nil, - }, - }, - "Invalid_Eventlog_Level": { - in: &pb.GetEventlogRequest{ - EventlogLevel: INVALID_EVENTLOG_LEVEL, - }, - expected: expectation{ - out: &pb.GetEventlogReply{}, - err: errors.New("rpc error: code = Unknown desc = Invalid Request"), - }, - }, - "Invalid_Eventlog_Category": { - in: &pb.GetEventlogRequest{ - EventlogLevel: pb.LEVEL_PAAS, - EventlogCategory: INVALID_EVENTLOG_CATEGORY, - }, - expected: expectation{ - out: &pb.GetEventlogReply{}, - err: errors.New("rpc error: code = Unknown desc = Invalid Request"), - }, - }, - "Request_on_SAAS_Level_Eventlog": { - in: &pb.GetEventlogRequest{ - EventlogLevel: pb.LEVEL_SAAS, - }, - expected: expectation{ - out: &pb.GetEventlogReply{ - EventlogDataLoc: "/run/ccnp-eventlog/eventlog.log", - }, - err: nil, - }, - }, - "Request_on_TPM_Eventlog_without_TPM_Support": { - in: &pb.GetEventlogRequest{ - EventlogLevel: pb.LEVEL_PAAS, - EventlogCategory: pb.CATEGORY_TPM_EVENTLOG, - }, - expected: expectation{ - out: &pb.GetEventlogReply{}, - err: errors.New("rpc error: code = Unknown desc = stat /sys/kernel/security/tpm0/binary_bios_measurements: no such file or directory"), - }, - }, - "Request_on_TPM_Eventlog_with_Options_without_TPM_support": { - in: &pb.GetEventlogRequest{ - EventlogLevel: pb.LEVEL_PAAS, - EventlogCategory: pb.CATEGORY_TPM_EVENTLOG, - StartPosition: 1, - Count: 5, - }, - expected: expectation{ - out: &pb.GetEventlogReply{}, - err: errors.New("rpc error: code = Unknown desc = stat /sys/kernel/security/tpm0/binary_bios_measurements: no such file or directory"), - }, - }, - "Request_on_Basic_TDX_Eventlog": { - in: &pb.GetEventlogRequest{ - EventlogLevel: pb.LEVEL_PAAS, - EventlogCategory: pb.CATEGORY_TDX_EVENTLOG, - }, - expected: expectation{ - out: &pb.GetEventlogReply{ - EventlogDataLoc: "/run/ccnp-eventlog/eventlog.log", - }, - err: nil, - }, - }, - "Request_on_TDX_Eventlog_with_options": { - in: &pb.GetEventlogRequest{ - EventlogLevel: pb.LEVEL_PAAS, - EventlogCategory: pb.CATEGORY_TDX_EVENTLOG, - StartPosition: 1, - Count: 5, - }, - expected: expectation{ - out: &pb.GetEventlogReply{ - EventlogDataLoc: "/run/ccnp-eventlog/eventlog.log", - }, - err: nil, - }, - }, - } - - for scenario, tt := range tests { - t.Run(scenario, func(t *testing.T) { - out, err := client.GetEventlog(ctx, tt.in) - if err != nil { - if tt.expected.err == nil { - t.Errorf("Err -> \nWant: nil\nGot: %q\n", err) - } else { - if tt.expected.err.Error() != err.Error() { - t.Errorf("Err -> \nWant: %q\nGot: %q\n", tt.expected.err, err) - } - } - } else { - if tt.expected.out.EventlogDataLoc != out.EventlogDataLoc { - t.Errorf("Out -> \nWant: %q\nGot : %q", tt.expected.out, out) - } - } - - }) - } -} diff --git a/service/measurement-server/Makefile b/service/measurement-server/Makefile deleted file mode 100644 index 87f3368..0000000 --- a/service/measurement-server/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2023, Intel Corporation. All rights reserved.
-# SPDX-License-Identifier: Apache-2.0 - -export GO111MODULE=on - -all: clean - CGO_ENABLED=1 GOOS=linux GOARCH=amd64 - @go build -tags netgo -o ./measurement-server ./server/server.go - -# The following is done this way as each patch on CI runs build and each merge runs deploy. So for build we don't need to build binary and hence -# no need to create a static binary with additional flags. However, for generating binary, additional build flags are necessary. This if used with -# mock plugin errors out for unit tests. So the seperation avoids the error. - -build: clean test cover -deploy: build - -.PHONY: test -test: clean - # remove race condition as workaround - # @go test -race ./... - @go test ./... - -format: - @go fmt ./... - -clean: - @find . -name "*so" -delete - @rm -f measurement-server coverage.html coverage.out - -.PHONY: cover -cover: - @go test -race ./... -coverprofile=coverage.out - @go tool cover -html=coverage.out -o coverage.html diff --git a/service/measurement-server/README.md b/service/measurement-server/README.md deleted file mode 100644 index bd292d3..0000000 --- a/service/measurement-server/README.md +++ /dev/null @@ -1,134 +0,0 @@ -# Service: CCNP Measurement Server - -Measurements are key assets in the confidential computing world for user to verify and determine the trustworthiness of the environment and its underlying platform. -Users can utilize different kinds of measurements to monitor or validate the operations performed within the platform. - -This service (which is actually a GRPC server) will provide such interface to fetch the measurements for confidential cloud native environments, including TDX RTMR measurements, TPM PCR measurements and TEE reports. - - - -## Introduction - -This service provides functionality to fetch measurements for confidential cloud native environments, both platform level(`PAAS` option) and container level (`SAAS` option). Using this service, user can fetch different -categories of measurements including: TDX RTMR measurements (`TDX_RTMR` option), TPM PCR measurements (`TPM` option) and TEE reports from different vendors (`TEE_REPORT` option). -Here shows the proto buf for the service: - -``` -enum TYPE { - PAAS = 0; - SAAS = 1; -} - -enum CATEGORY { - TEE_REPORT = 0; - TPM = 1; - TDX_RTMR = 2; -} - -message GetMeasurementRequest { - TYPE measurement_type = 1; - CATEGORY measurement_category = 2; - string report_data = 3; - int32 register_index = 4; - -} - -message GetMeasurementReply { - string measurement = 1; -} - -service Measurement { - rpc GetMeasurement (GetMeasurementRequest) returns (GetMeasurementReply) {} -} -``` - -To select different level and category of measurements, user shall send out request with different settings. -User can find sample request in the Testing section. - -The collected measurements are returned as json string to the client. - - - -## Installation - -The Measurement service can be deployed as either DaemonSet or sidecar in different user scenarios within a kubernetes cluster. - - -### Prerequisite - -User need to have a kubernetes cluster ready to deploy the services. To simplify the deployment process, we provide Helm as one of the options to deploy the service. Please install Helm by following the [Helm official guide](https://helm.sh/docs/intro/install/). However, user can also use the yaml files located in the manifests folder for deployment. -Also, the ccnp device plugin need to installed before the installation of measurement server. Please refer to its [deployment guide](../../device-plugin/ccnp-device-plugin/README.md) for installation. - -### Build docker image - -The dockerfile for the service can be found under `container/ccnp-measurement-server` directory. Use the following command to build the image: - -``` -cd ../.. -docker build -t ccnp-measurement-server: -f container/ccnp-measurement-server/Dockerfile . -``` -> Note: if you are using containerd as the default runtime for kubernetes. Please remember to use the following commands to import the image into containerd first: -``` -docker save -o ccnp-measurement-server.tar ccnp-measurement-server: -ctr -n=k8s.io image import ccnp-measurement-server.tar -``` - -### Deploy as DaemonSet - -In the scenario of confidential kubernetes cluster, it is nice to deploy the measurement service as a DaemonSet to serve all the applications living inside that cluster node. -Run the following command to deploy the service using helm chart: - -``` -cd ../../deployment -helm install charts/measurement-server --generate-name -``` -> Note: `ccnp` namespace may get duplicated in the case user installed multiple ccnp services. Please define the `namespaceCreate` option as `false` in the values.yaml before install the helm chart if certain case happens. - -User can also choose the manifests file to deploy the service: -``` -cd ../../deployment/manifests -kubectl create -f namespace.yaml -kubectl create -f measurement-server-deployment.yaml -``` - -### Deploy as Sidecar - -In the scenario of confidential containers, it is nice to deploy the measurement service as sidecar working along with the confidential containers. -The deployment helm chart and manifests are still in progress. - -### User application deployment - -Make sure that the user application requests such resource in the yaml file to take use of sdk to contact the measurement server: `tdx.intel.com/tdx-guest: 1`. - - - -## Testing - -User can play with the service on host from the source code by following the steps below: - -1. Start the measurement service - -``` -cd service/measurement-server -make all - -./measurement-server -``` - -2. Play with the service - -Use the `grpcurl` as the tool to play with the service. Please follow the [official documentation](https://github.com/fullstorydev/grpcurl) to install grpcurl. - -Get TDX RTMR measurement of register index equal to 0: -``` -grpcurl -plaintext -d '{"measurement_type": 0, "measurement_category": 2, "register_index": 0}' -unix /run/ccnp/uds/measurement.sock measurement.Measurement/GetMeasurement -``` - -Get TEE report according to the platform capability: -``` -grpcurl -plaintext -d '{"measurement_type": 0, "measurement_category": 0}' -unix /run/ccnp/uds/measurement.sock measurement.Measurement/GetMeasurement -``` - -User can find the fetched measurements as base64 encoded string returned as response. - - diff --git a/service/measurement-server/go.mod b/service/measurement-server/go.mod deleted file mode 100644 index 505a189..0000000 --- a/service/measurement-server/go.mod +++ /dev/null @@ -1,18 +0,0 @@ -module github.com/intel/confidential-cloud-native-primitives/service/measurement-server - -go 1.20 - -require ( - github.com/golang/protobuf v1.5.3 - github.com/pkg/errors v0.9.1 - golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 - google.golang.org/grpc v1.56.3 -) - -require ( - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect - google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect - google.golang.org/protobuf v1.30.0 // indirect -) diff --git a/service/measurement-server/go.sum b/service/measurement-server/go.sum deleted file mode 100644 index 26a368b..0000000 --- a/service/measurement-server/go.sum +++ /dev/null @@ -1,24 +0,0 @@ -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw= -golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A= -google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU= -google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc= -google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/service/measurement-server/proto/measurement-server.pb.go b/service/measurement-server/proto/measurement-server.pb.go deleted file mode 100644 index a8c6c12..0000000 --- a/service/measurement-server/proto/measurement-server.pb.go +++ /dev/null @@ -1,213 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: proto/measurement-server.proto - -package getMeasurement - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type TYPE int32 - -const ( - TYPE_PAAS TYPE = 0 - TYPE_SAAS TYPE = 1 -) - -var TYPE_name = map[int32]string{ - 0: "PAAS", - 1: "SAAS", -} - -var TYPE_value = map[string]int32{ - "PAAS": 0, - "SAAS": 1, -} - -func (x TYPE) String() string { - return proto.EnumName(TYPE_name, int32(x)) -} - -func (TYPE) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_52ee6f800ca253e4, []int{0} -} - -type CATEGORY int32 - -const ( - CATEGORY_TEE_REPORT CATEGORY = 0 - CATEGORY_TPM CATEGORY = 1 - CATEGORY_TDX_RTMR CATEGORY = 2 -) - -var CATEGORY_name = map[int32]string{ - 0: "TEE_REPORT", - 1: "TPM", - 2: "TDX_RTMR", -} - -var CATEGORY_value = map[string]int32{ - "TEE_REPORT": 0, - "TPM": 1, - "TDX_RTMR": 2, -} - -func (x CATEGORY) String() string { - return proto.EnumName(CATEGORY_name, int32(x)) -} - -func (CATEGORY) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_52ee6f800ca253e4, []int{1} -} - -type GetMeasurementRequest struct { - MeasurementType TYPE `protobuf:"varint,1,opt,name=measurement_type,json=measurementType,proto3,enum=measurement.TYPE" json:"measurement_type,omitempty"` - MeasurementCategory CATEGORY `protobuf:"varint,2,opt,name=measurement_category,json=measurementCategory,proto3,enum=measurement.CATEGORY" json:"measurement_category,omitempty"` - ReportData string `protobuf:"bytes,3,opt,name=report_data,json=reportData,proto3" json:"report_data,omitempty"` - RegisterIndex int32 `protobuf:"varint,4,opt,name=register_index,json=registerIndex,proto3" json:"register_index,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMeasurementRequest) Reset() { *m = GetMeasurementRequest{} } -func (m *GetMeasurementRequest) String() string { return proto.CompactTextString(m) } -func (*GetMeasurementRequest) ProtoMessage() {} -func (*GetMeasurementRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_52ee6f800ca253e4, []int{0} -} - -func (m *GetMeasurementRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMeasurementRequest.Unmarshal(m, b) -} -func (m *GetMeasurementRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMeasurementRequest.Marshal(b, m, deterministic) -} -func (m *GetMeasurementRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMeasurementRequest.Merge(m, src) -} -func (m *GetMeasurementRequest) XXX_Size() int { - return xxx_messageInfo_GetMeasurementRequest.Size(m) -} -func (m *GetMeasurementRequest) XXX_DiscardUnknown() { - xxx_messageInfo_GetMeasurementRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMeasurementRequest proto.InternalMessageInfo - -func (m *GetMeasurementRequest) GetMeasurementType() TYPE { - if m != nil { - return m.MeasurementType - } - return TYPE_PAAS -} - -func (m *GetMeasurementRequest) GetMeasurementCategory() CATEGORY { - if m != nil { - return m.MeasurementCategory - } - return CATEGORY_TEE_REPORT -} - -func (m *GetMeasurementRequest) GetReportData() string { - if m != nil { - return m.ReportData - } - return "" -} - -func (m *GetMeasurementRequest) GetRegisterIndex() int32 { - if m != nil { - return m.RegisterIndex - } - return 0 -} - -type GetMeasurementReply struct { - Measurement string `protobuf:"bytes,1,opt,name=measurement,proto3" json:"measurement,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetMeasurementReply) Reset() { *m = GetMeasurementReply{} } -func (m *GetMeasurementReply) String() string { return proto.CompactTextString(m) } -func (*GetMeasurementReply) ProtoMessage() {} -func (*GetMeasurementReply) Descriptor() ([]byte, []int) { - return fileDescriptor_52ee6f800ca253e4, []int{1} -} - -func (m *GetMeasurementReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetMeasurementReply.Unmarshal(m, b) -} -func (m *GetMeasurementReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetMeasurementReply.Marshal(b, m, deterministic) -} -func (m *GetMeasurementReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetMeasurementReply.Merge(m, src) -} -func (m *GetMeasurementReply) XXX_Size() int { - return xxx_messageInfo_GetMeasurementReply.Size(m) -} -func (m *GetMeasurementReply) XXX_DiscardUnknown() { - xxx_messageInfo_GetMeasurementReply.DiscardUnknown(m) -} - -var xxx_messageInfo_GetMeasurementReply proto.InternalMessageInfo - -func (m *GetMeasurementReply) GetMeasurement() string { - if m != nil { - return m.Measurement - } - return "" -} - -func init() { - proto.RegisterEnum("measurement.TYPE", TYPE_name, TYPE_value) - proto.RegisterEnum("measurement.CATEGORY", CATEGORY_name, CATEGORY_value) - proto.RegisterType((*GetMeasurementRequest)(nil), "measurement.GetMeasurementRequest") - proto.RegisterType((*GetMeasurementReply)(nil), "measurement.GetMeasurementReply") -} - -func init() { proto.RegisterFile("proto/measurement-server.proto", fileDescriptor_52ee6f800ca253e4) } - -var fileDescriptor_52ee6f800ca253e4 = []byte{ - // 379 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x92, 0x4d, 0x6f, 0xd3, 0x40, - 0x10, 0x86, 0xe3, 0x36, 0x40, 0x3a, 0x01, 0x63, 0xb6, 0x54, 0xb2, 0x7a, 0x00, 0xcb, 0x12, 0x52, - 0x54, 0xc9, 0xb6, 0x28, 0x07, 0x2e, 0x5c, 0x42, 0x6b, 0x15, 0x0e, 0x51, 0xad, 0xed, 0x1e, 0x12, - 0x2e, 0xd6, 0xc6, 0x1e, 0xcc, 0x4a, 0xfe, 0x62, 0xbd, 0x8e, 0xf0, 0x2f, 0xe6, 0x6f, 0x20, 0x3b, - 0x44, 0xac, 0x51, 0xd4, 0xdb, 0xe8, 0x99, 0x8f, 0x9d, 0x77, 0xf6, 0x85, 0x37, 0xb5, 0xac, 0x54, - 0x15, 0x14, 0xc8, 0x9b, 0x56, 0x62, 0x81, 0xa5, 0xf2, 0x1a, 0x94, 0x3b, 0x94, 0xfe, 0x90, 0x20, - 0x73, 0x2d, 0xe3, 0xfe, 0x36, 0xe0, 0xe2, 0x0e, 0xd5, 0xea, 0x1f, 0xa2, 0xf8, 0xb3, 0xc5, 0x46, - 0x91, 0x4f, 0x60, 0x69, 0x85, 0xb1, 0xea, 0x6a, 0xb4, 0x0d, 0xc7, 0x58, 0x98, 0xd7, 0xaf, 0x7c, - 0x2d, 0xe1, 0xb3, 0x4d, 0x14, 0xd2, 0x97, 0x1a, 0x61, 0x5d, 0x8d, 0xe4, 0x0b, 0xbc, 0xd6, 0xbb, - 0x13, 0xae, 0x30, 0xab, 0x64, 0x67, 0x9f, 0x0c, 0x13, 0x2e, 0x46, 0x13, 0x6e, 0x96, 0x2c, 0xbc, - 0xbb, 0xa7, 0x1b, 0x7a, 0xae, 0xd1, 0x9b, 0xbf, 0x1d, 0xe4, 0x2d, 0xcc, 0x25, 0xd6, 0x95, 0x54, - 0x71, 0xca, 0x15, 0xb7, 0x4f, 0x1d, 0x63, 0x71, 0x46, 0x61, 0x8f, 0x6e, 0xb9, 0xe2, 0xe4, 0x1d, - 0x98, 0x12, 0x33, 0xd1, 0x28, 0x94, 0xb1, 0x28, 0x53, 0xfc, 0x65, 0x4f, 0x1d, 0x63, 0xf1, 0x84, - 0xbe, 0x38, 0xd0, 0xaf, 0x3d, 0x74, 0x3f, 0xc2, 0xf9, 0xff, 0x42, 0xeb, 0xbc, 0x23, 0x0e, 0xe8, - 0xf7, 0x18, 0x14, 0x9e, 0x51, 0x1d, 0x5d, 0x5d, 0xc2, 0xb4, 0xd7, 0x48, 0x66, 0x30, 0x8d, 0x96, - 0xcb, 0x07, 0x6b, 0xd2, 0x47, 0x0f, 0x7d, 0x64, 0x5c, 0xbd, 0x87, 0xd9, 0x61, 0x7b, 0x62, 0x02, - 0xb0, 0x30, 0x8c, 0x69, 0x18, 0xdd, 0x53, 0x66, 0x4d, 0xc8, 0x33, 0x38, 0x65, 0xd1, 0xca, 0x32, - 0xc8, 0x73, 0x98, 0xb1, 0xdb, 0x75, 0x4c, 0xd9, 0x8a, 0x5a, 0x27, 0xd7, 0x19, 0xcc, 0xb5, 0x25, - 0xc8, 0x1a, 0xcc, 0xf1, 0x5a, 0xc4, 0x1d, 0x1d, 0xe7, 0xe8, 0xe7, 0x5c, 0x3a, 0x8f, 0xd6, 0xd4, - 0x79, 0xe7, 0x4e, 0x3e, 0x67, 0xdf, 0x30, 0x13, 0xea, 0x47, 0xbb, 0xf5, 0x93, 0xaa, 0x08, 0x44, - 0xa9, 0x30, 0x0f, 0x92, 0xaa, 0xfc, 0x2e, 0x52, 0x2c, 0x95, 0xe0, 0xb9, 0x97, 0xe4, 0x55, 0x9b, - 0x7a, 0x25, 0x57, 0x62, 0x87, 0x5e, 0x2d, 0x45, 0x21, 0xfa, 0xa8, 0x09, 0x7a, 0xb7, 0x88, 0x04, - 0x8f, 0x38, 0x28, 0xd8, 0x5b, 0x2b, 0x1b, 0xbd, 0xb7, 0x7d, 0x3a, 0xd0, 0x0f, 0x7f, 0x02, 0x00, - 0x00, 0xff, 0xff, 0x72, 0x3f, 0x43, 0x37, 0x79, 0x02, 0x00, 0x00, -} diff --git a/service/measurement-server/proto/measurement-server.proto b/service/measurement-server/proto/measurement-server.proto deleted file mode 120000 index 2cbc8d1..0000000 --- a/service/measurement-server/proto/measurement-server.proto +++ /dev/null @@ -1 +0,0 @@ -../../../api/measurement-server.proto \ No newline at end of file diff --git a/service/measurement-server/proto/measurement-server_grpc.pb.go b/service/measurement-server/proto/measurement-server_grpc.pb.go deleted file mode 100644 index 1465aa0..0000000 --- a/service/measurement-server/proto/measurement-server_grpc.pb.go +++ /dev/null @@ -1,105 +0,0 @@ -// Code generated by protoc-gen-go-grpc. DO NOT EDIT. -// versions: -// - protoc-gen-go-grpc v1.2.0 -// - protoc v3.11.4 -// source: proto/measurement-server.proto - -package getMeasurement - -import ( - context "context" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" -) - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -// Requires gRPC-Go v1.32.0 or later. -const _ = grpc.SupportPackageIsVersion7 - -// MeasurementClient is the client API for Measurement service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. -type MeasurementClient interface { - GetMeasurement(ctx context.Context, in *GetMeasurementRequest, opts ...grpc.CallOption) (*GetMeasurementReply, error) -} - -type measurementClient struct { - cc grpc.ClientConnInterface -} - -func NewMeasurementClient(cc grpc.ClientConnInterface) MeasurementClient { - return &measurementClient{cc} -} - -func (c *measurementClient) GetMeasurement(ctx context.Context, in *GetMeasurementRequest, opts ...grpc.CallOption) (*GetMeasurementReply, error) { - out := new(GetMeasurementReply) - err := c.cc.Invoke(ctx, "/measurement.Measurement/GetMeasurement", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// MeasurementServer is the server API for Measurement service. -// All implementations must embed UnimplementedMeasurementServer -// for forward compatibility -type MeasurementServer interface { - GetMeasurement(context.Context, *GetMeasurementRequest) (*GetMeasurementReply, error) - mustEmbedUnimplementedMeasurementServer() -} - -// UnimplementedMeasurementServer must be embedded to have forward compatible implementations. -type UnimplementedMeasurementServer struct { -} - -func (UnimplementedMeasurementServer) GetMeasurement(context.Context, *GetMeasurementRequest) (*GetMeasurementReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetMeasurement not implemented") -} -func (UnimplementedMeasurementServer) mustEmbedUnimplementedMeasurementServer() {} - -// UnsafeMeasurementServer may be embedded to opt out of forward compatibility for this service. -// Use of this interface is not recommended, as added methods to MeasurementServer will -// result in compilation errors. -type UnsafeMeasurementServer interface { - mustEmbedUnimplementedMeasurementServer() -} - -func RegisterMeasurementServer(s grpc.ServiceRegistrar, srv MeasurementServer) { - s.RegisterService(&Measurement_ServiceDesc, srv) -} - -func _Measurement_GetMeasurement_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetMeasurementRequest) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(MeasurementServer).GetMeasurement(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/measurement.Measurement/GetMeasurement", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(MeasurementServer).GetMeasurement(ctx, req.(*GetMeasurementRequest)) - } - return interceptor(ctx, in, info, handler) -} - -// Measurement_ServiceDesc is the grpc.ServiceDesc for Measurement service. -// It's only intended for direct use with grpc.RegisterService, -// and not to be introspected or modified (even as a copy) -var Measurement_ServiceDesc = grpc.ServiceDesc{ - ServiceName: "measurement.Measurement", - HandlerType: (*MeasurementServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "GetMeasurement", - Handler: _Measurement_GetMeasurement_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "proto/measurement-server.proto", -} diff --git a/service/measurement-server/resources/base.go b/service/measurement-server/resources/base.go deleted file mode 100644 index 34a2e8b..0000000 --- a/service/measurement-server/resources/base.go +++ /dev/null @@ -1,76 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - pkgerrors "github.com/pkg/errors" - "strings" -) - -const ( - TDX_FLAG = "tdx" - SEV_FLAG = "sev" -) - -var DeviceNotFoundErr = pkgerrors.New("No applicable device found.") - -type BaseTeeInterface interface { - GetType() string - FindDeviceAvailable() (string, error) - GetReport(device string, data string) (string, error) -} - -type BaseTeeResource struct { - Type string -} - -func NewBaseTeeResource() BaseTeeResource { - return BaseTeeResource{ - Type: "Base", - } -} - -func (r *BaseTeeResource) GetType() string { - return r.Type -} - -func (r *BaseTeeResource) FindDeviceAvailable() (string, error) { - tdxResource := NewTdxResource() - device, err := tdxResource.FindDeviceAvailable() - if err == nil { - return device, nil - } - - sevResource := NewSevResource() - device, err = sevResource.FindDeviceAvailable() - if err == nil { - return device, nil - } - - return "", DeviceNotFoundErr -} - -func (r *BaseTeeResource) GetReport(device string, data string) (string, error) { - - var report string - var err error - - if strings.Contains(device, TDX_FLAG) { - tdx := NewTdxResource() - report, err = tdx.GetReport(device, data) - if err != nil { - return "", err - } - } else if strings.Contains(device, SEV_FLAG) { - sev := NewSevResource() - report, err = sev.GetReport(device, data) - if err != nil { - return "", err - } - } - - return report, nil -} diff --git a/service/measurement-server/resources/base_test.go b/service/measurement-server/resources/base_test.go deleted file mode 100644 index d15f542..0000000 --- a/service/measurement-server/resources/base_test.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "encoding/base64" - "golang.org/x/exp/slices" - "testing" -) - -var ( - TDX_DEVICE_LIST = []string{DEVICE_NODE_NAME_1_0, DEVICE_NODE_NAME_1_5} -) - -func TestFindDeviceAvailable(t *testing.T) { - r := NewBaseTeeResource() - - device, err := r.FindDeviceAvailable() - - if err != nil || !slices.Contains(TDX_DEVICE_LIST, device) { - t.Fatalf(`FindDeviceAvailable() = %s, %v want TDX device, %v`, device, err, nil) - } -} - -func TestGetReport(t *testing.T) { - r := NewBaseTeeResource() - - data := "test" - device, _ := r.FindDeviceAvailable() - - report, err := r.GetReport(device, data) - if err != nil { - t.Fatalf(`GetReport(device, data) = %s, %v want report and %v`, - report, err, nil) - } - _, err = base64.StdEncoding.DecodeString(report) - if err != nil { - t.Fatalf(`GetReport(device, data) = %s, %v want base64 encoded report and %v`, - report, err, nil) - } -} diff --git a/service/measurement-server/resources/sev.go b/service/measurement-server/resources/sev.go deleted file mode 100644 index d038600..0000000 --- a/service/measurement-server/resources/sev.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "log" - "os" -) - -const ( - // The device fd for AMD SEV - DEVICE_NODE_NAME_1 = "/dev/sev-guest" - DEVICE_NODE_NAME_2 = "/dev/sev" -) - -type SevResource struct { - BaseTeeResource -} - -func NewSevResource() *SevResource { - return &SevResource{ - BaseTeeResource{ - Type: "AMD SEV", - }, - } -} - -func (r *SevResource) FindDeviceAvailable() (string, error) { - - if _, err := os.Stat(DEVICE_NODE_NAME_1); err == nil { - return DEVICE_NODE_NAME_1, nil - } - - if _, err := os.Stat(DEVICE_NODE_NAME_2); err == nil { - return DEVICE_NODE_NAME_2, nil - } - - return "", DeviceNotFoundErr -} - -func (r *SevResource) GetReport(device string, data string) (string, error) { - - /* - // Open SEV device fd to get prepared - deviceNode, err := os.OpenFile(device, os.O_RDWR, 0644) - if err != nil { - return "", err - } - - // TODO: check if there can be a data attached to SEV report - if len(data) > REPORT_DATA_LEN { - err = pkgerrors.New("Report data with invalid length.") - return "", err - }*/ - log.Println("Not implemented") - return "", nil -} diff --git a/service/measurement-server/resources/sev_test.go b/service/measurement-server/resources/sev_test.go deleted file mode 100644 index d86138c..0000000 --- a/service/measurement-server/resources/sev_test.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "testing" -) - -func TestFindSEVDeviceAvailable(t *testing.T) { - r := NewSevResource() - - _, err := r.FindDeviceAvailable() - if err.Error() != DeviceNotFoundErr.Error() { - t.Fatalf(`FindDeviceAvailable() = %v want %v`, - err, DeviceNotFoundErr) - } -} - -func TestGetSEVReport(t *testing.T) { - r := NewSevResource() - device := DEVICE_NODE_NAME_1 - data := "" - - _, err := r.GetReport(device, data) - if err != nil { - t.Fatalf(`GetReport() = %v want %v`, - err, nil) - } -} diff --git a/service/measurement-server/resources/tdx.go b/service/measurement-server/resources/tdx.go deleted file mode 100644 index 3ac02a1..0000000 --- a/service/measurement-server/resources/tdx.go +++ /dev/null @@ -1,212 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "encoding/base64" - "log" - "os" - "syscall" - "unsafe" - - pkgerrors "github.com/pkg/errors" -) - -const ( - - // The name of the device in different kernel version - DEVICE_NODE_NAME_DEPRECATED = "/dev/tdx-attest" - DEVICE_NODE_NAME_1_0 = "/dev/tdx-guest" - DEVICE_NODE_NAME_1_5 = "/dev/tdx_guest" - - // The length of report data - REPORT_DATA_LEN = 64 - // The length of TDX report - TDX_REPORT_LEN = 1024 - // The length of Data can be extended into RTMR - TDX_EXTEND_RTMR_DATA_LEN = 48 - - /*The device operators for tdx v1.0 - Reference: TDX_CMD_GET_REPORT = _IOWR('T', 0x01, __u64) - defined in arch/x86/include/uapi/asm/tdx.h in kernel source - */ - TDX_CMD_GET_REPORT_V1_0 = 0xc0085401 - - /* The device operators for tdx v1.5 - Reference: TDX_CMD_GET_REPORT0 = _IOWR('T', 1, struct tdx_report_req) - defined in include/uapi/linux/tdx-guest.h in kernel source - */ - TDX_CMD_GET_REPORT0_V1_5 = 0xc4405401 - - RTMR_0_OFFSET = 0x2d0 - RTMR_1_OFFSET = 0x300 - RTMR_2_OFFSET = 0x330 - RTMR_3_OFFSET = 0x360 - - RTMR_LEN = 0x30 -) - -var TdxGetReportErr = pkgerrors.New("Failed to get TDX report.") -var InvalidRtmrIndexErr = pkgerrors.New("Invalid RTMR index used.") - -type TdxReportReq struct { - SubType uint8 - ReportData uint64 - RpdLen uint32 - TdReport uint64 - TdrLen uint32 -} - -type TdxResource struct { - BaseTeeResource -} - -func NewTdxResource() *TdxResource { - return &TdxResource{ - BaseTeeResource{ - Type: "Intel TDX", - }, - } -} - -func NewTdxReportReq(data string) TdxReportReq { - d := make([]byte, REPORT_DATA_LEN) - copy(d, []byte(data)) - - r := make([]byte, TDX_REPORT_LEN) - - return TdxReportReq{ - SubType: uint8(0), - ReportData: uint64(uintptr(unsafe.Pointer(&d[0]))), - RpdLen: uint32(REPORT_DATA_LEN), - TdReport: uint64(uintptr(unsafe.Pointer(&r[0]))), - TdrLen: uint32(TDX_REPORT_LEN), - } -} - -func NewTdxReportReq0(data string) []byte { - d := make([]byte, REPORT_DATA_LEN+TDX_REPORT_LEN) - copy(d, []byte(data)) - return d -} - -func (r *TdxResource) FindDeviceAvailable() (string, error) { - - if _, err := os.Stat(DEVICE_NODE_NAME_DEPRECATED); err == nil { - log.Printf("Deprecated device node %s, please upgrade to use %s or %s", - DEVICE_NODE_NAME_DEPRECATED, DEVICE_NODE_NAME_1_0, DEVICE_NODE_NAME_1_5) - return "", DeviceNotFoundErr - } - - if _, err := os.Stat(DEVICE_NODE_NAME_1_0); err == nil { - return DEVICE_NODE_NAME_1_0, nil - } - - if _, err := os.Stat(DEVICE_NODE_NAME_1_5); err == nil { - return DEVICE_NODE_NAME_1_5, nil - } - - return "", DeviceNotFoundErr -} - -func (r *TdxResource) GetReport(device string, data string) (string, error) { - - var report string - - /* Open TDX device fd to get prepared for TDVM call*/ - deviceNode, err := os.OpenFile(device, os.O_RDWR, 0644) - if err != nil { - return "", err - } - - if len(data) > REPORT_DATA_LEN { - err = pkgerrors.New("Report data with invalid length.") - return "", err - } - - if device == DEVICE_NODE_NAME_1_0 { - report, err = getTdxReport(deviceNode, data) - if err != nil { - return "", err - } - } else { - report, err = getTdxReport0(deviceNode, data) - if err != nil { - return "", err - } - } - - return report, nil -} - -func getTdxReport(deviceNode *os.File, data string) (string, error) { - - req := NewTdxReportReq(data) - _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(deviceNode.Fd()), - uintptr(TDX_CMD_GET_REPORT_V1_0), uintptr(unsafe.Pointer(&req))) - if errno != 0 { - return "", TdxGetReportErr - } - - td_report_value := make([]byte, TDX_REPORT_LEN) - copy(td_report_value, (*[1 << 30]byte)(unsafe.Pointer(uintptr(req.TdReport)))[:TDX_REPORT_LEN]) - report_string := base64.StdEncoding.EncodeToString(td_report_value) - - return report_string, nil -} - -func getTdxReport0(deviceNode *os.File, data string) (string, error) { - - req := NewTdxReportReq0(data) - _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(deviceNode.Fd()), - uintptr(TDX_CMD_GET_REPORT0_V1_5), uintptr(unsafe.Pointer(&req[0]))) - if errno != 0 { - return "", TdxGetReportErr - } - - report := base64.StdEncoding.EncodeToString(req[REPORT_DATA_LEN:]) - return report, nil -} - -func (r *TdxResource) GetRTMRMeasurement(device string, data string, index int) (string, error) { - - if index < 0 || index > 3 { - return "", InvalidRtmrIndexErr - } - - report, err := r.GetReport(device, data) - if err != nil { - return "", err - } - - measurement, err := collectRtmrMeasurement(report, index) - if err != nil { - return "", err - } - - return base64.StdEncoding.EncodeToString(measurement), nil -} - -func collectRtmrMeasurement(report string, index int) ([]byte, error) { - - r, err := base64.StdEncoding.DecodeString(report) - if err != nil { - return []byte{}, err - } - value := make([]byte, RTMR_LEN) - - switch index { - case 0: - value = r[RTMR_0_OFFSET : RTMR_0_OFFSET+RTMR_LEN] - case 1: - value = r[RTMR_1_OFFSET : RTMR_1_OFFSET+RTMR_LEN] - case 2: - value = r[RTMR_2_OFFSET : RTMR_2_OFFSET+RTMR_LEN] - case 3: - value = r[RTMR_3_OFFSET : RTMR_3_OFFSET+RTMR_LEN] - } - return value, nil -} diff --git a/service/measurement-server/resources/tdx_test.go b/service/measurement-server/resources/tdx_test.go deleted file mode 100644 index 8ec4b0f..0000000 --- a/service/measurement-server/resources/tdx_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "encoding/base64" - pkgerrors "github.com/pkg/errors" - "golang.org/x/exp/slices" - "testing" -) - -func TestFindTDXDeviceAvailable(t *testing.T) { - r := NewTdxResource() - - device, err := r.FindDeviceAvailable() - if err != nil || !slices.Contains(TDX_DEVICE_LIST, device) { - t.Fatalf(`FindDeviceAvailable() = %s, %v want valid tdx device and nil`, - device, err) - } -} - -func TestTDXGetReport(t *testing.T) { - r := NewTdxResource() - - device, _ := r.FindDeviceAvailable() - report, err := r.GetReport(device, "") - if err != nil { - t.Fatalf(`GetReport(device, "") = %s, %v want report and nil`, - report, err) - } - _, err = base64.StdEncoding.DecodeString(report) - if err != nil { - t.Fatalf(`GetReport(device, "") = %s, %v want base64 encoded report and nil`, - report, err) - } -} - -func TestGetRTMRMeasurement(t *testing.T) { - r := NewTdxResource() - - device, _ := r.FindDeviceAvailable() - index := 0 - - measurement, err := r.GetRTMRMeasurement(device, "", index) - if err != nil { - t.Fatalf(`GetRTMRMeasurement(device, "", 0) = %s, %v want measurement, %v`, - measurement, err, nil) - } - _, err = base64.StdEncoding.DecodeString(measurement) - if err != nil { - t.Fatalf(`GetRTMRMeasurement(device, "", 0) = %s, %v want base64 encoded measurement, %v`, - measurement, err, nil) - } -} - -func TestCollectRtmrMeasurement(t *testing.T) { - report := "gQAAAAAAAAAAAAAAAAAAAAEBAQEB/wABAAAAAAAAAAA2OBU1hr5liB7Hcj2fQyCokisfxMHJ1OaXAQCQ/DTfh/IWWhhEH9TLXg4wlHIYCs8Ku50kbzi8ZyJBxnA+PZyuM3ulswD3Zxhhzt9AelPfSZX06h7XRu2m1aOGrtD3tQ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADrxjc/2ZBFYiP3mNWUILLmoXf+lHqdGIMjj5Sv/hn8C/8BAwAAAAAAAAEBAAAAAAAAAAAAAAAAAFi1VbaJLemWgQThKktgTVRGjKyORNj10YBYB8YItDdufnvvDf5alim7S2hZcvwDIgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAQAAAAAOcaBgAAAAAApKADNGxaGab9JQRx6HK9Bx2MktdDGr2kY0F4CKFzg6oNQph4FLyS9fWcYES2d/UUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnxfdBYPsEXhJQLRMcCfs30lC9XhkJEd1WAGCYlRFWrk9kOE8AD1XDT557A451xHsbR8pW9kYqecaRNV4+V4HjBX5yzX1YJhMUx5ErBFMTU4HF4Bsk9Gk3raULoSQFNCt6NfjSQvWDZug3rNW8HHa1PEUTfNH1mVexFvyDJ7rFpZ5MHrjg8aslqTue2ojc/uAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==" - index := 0 - sample_measurement, _ := base64.StdEncoding.DecodeString("nxfdBYPsEXhJQLRMcCfs30lC9XhkJEd1WAGCYlRFWrk9kOE8AD1XDT557A451xHs") - - measurement, err := collectRtmrMeasurement(report, index) - encoded_measurement := base64.StdEncoding.EncodeToString(measurement) - - if err != nil || encoded_measurement != "nxfdBYPsEXhJQLRMcCfs30lC9XhkJEd1WAGCYlRFWrk9kOE8AD1XDT557A451xHs" { - t.Fatalf(`collectRtmrMeasurement(report, 0) = %v, %v want %v, %v`, - measurement, err, sample_measurement, nil) - } -} - -func TestGetRTMRMeasurementWithInvalidIndex(t *testing.T) { - r := NewTdxResource() - - device, _ := r.FindDeviceAvailable() - index := 5 - - _, err := r.GetRTMRMeasurement(device, "", index) - if err.Error() != "Invalid RTMR index used." { - t.Fatalf(`GetRTMRMeasurement(device, "", 5) = %v want, %v`, - err, pkgerrors.New("Invalid RTMR index used.")) - } -} diff --git a/service/measurement-server/resources/tpm.go b/service/measurement-server/resources/tpm.go deleted file mode 100644 index 1dd406c..0000000 --- a/service/measurement-server/resources/tpm.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "log" - "os" -) - -const ( - // The device fd for AMD SEV - DEVICE_NODE_NAME_TPM = "/dev/tpm0" -) - -func findDeviceAvailable() (string, error) { - - if _, err := os.Stat(DEVICE_NODE_NAME_TPM); err == nil { - return DEVICE_NODE_NAME_TPM, nil - } - - return "", DeviceNotFoundErr -} - -func GetTpmMeasurement(index int) (string, error) { - - _, err := findDeviceAvailable() - if err != nil { - return "", err - } - - /* - // Open TPM device fd to get prepared - deviceNode, err := os.OpenFile(device, os.O_RDWR, 0644) - if err != nil { - return "", err - } - */ - log.Println("Not implemented") - return "", nil - -} diff --git a/service/measurement-server/resources/tpm_test.go b/service/measurement-server/resources/tpm_test.go deleted file mode 100644 index 51e3942..0000000 --- a/service/measurement-server/resources/tpm_test.go +++ /dev/null @@ -1,29 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package resources - -import ( - "testing" -) - -func TestFindTPMDeviceAvailable(t *testing.T) { - - _, err := findDeviceAvailable() - if err.Error() != DeviceNotFoundErr.Error() { - t.Fatalf(`FindDeviceAvailable() = %v want %v`, - err, DeviceNotFoundErr) - } -} - -func TestGetTpmMeasurement(t *testing.T) { - index := 0 - - _, err := GetTpmMeasurement(index) - if err.Error() != DeviceNotFoundErr.Error() { - t.Fatalf(`GetReport() = %v want %v`, - err, DeviceNotFoundErr) - } -} diff --git a/service/measurement-server/server/server.go b/service/measurement-server/server/server.go deleted file mode 100644 index 9fdd627..0000000 --- a/service/measurement-server/server/server.go +++ /dev/null @@ -1,155 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ - -package main - -import ( - "context" - "log" - "net" - "os" - - "google.golang.org/grpc" - "google.golang.org/grpc/health" - "google.golang.org/grpc/health/grpc_health_v1" - "google.golang.org/grpc/reflection" - - pb "github.com/intel/confidential-cloud-native-primitives/service/measurement-server/proto" - resources "github.com/intel/confidential-cloud-native-primitives/service/measurement-server/resources" - pkgerrors "github.com/pkg/errors" -) - -var ( - InvalidRequestErr = pkgerrors.New("Invalid Request") -) - -const ( - protocol = "unix" - sockAddr = "/run/ccnp/uds/measurement.sock" - MAX_CONCURRENT_STREAMS = 100 -) - -type measurementServer struct { - pb.UnimplementedMeasurementServer -} - -func getContainerMeasurement(measurementReq *pb.GetMeasurementRequest) (string, error) { - // not implemented - log.Println("Not implemented.") - return "", nil -} - -func getPaasMeasurement(measurementReq *pb.GetMeasurementRequest) (string, error) { - var category pb.CATEGORY - var measurement string - var err error - - category = measurementReq.MeasurementCategory - - switch category { - case pb.CATEGORY_TEE_REPORT: - measurement, err = getTeeReport(measurementReq) - case pb.CATEGORY_TDX_RTMR: - var device string - r := resources.NewTdxResource() - device, err = r.FindDeviceAvailable() - if err != nil { - return "", err - } - measurement, err = r.GetRTMRMeasurement(device, measurementReq.ReportData, int(measurementReq.RegisterIndex)) - case pb.CATEGORY_TPM: - measurement, err = resources.GetTpmMeasurement(int(measurementReq.RegisterIndex)) - default: - log.Println("Invalid measurement category.") - return "", InvalidRequestErr - } - return measurement, err -} - -func getTeeReport(measurementReq *pb.GetMeasurementRequest) (string, error) { - - reportData := measurementReq.ReportData - - r := resources.NewBaseTeeResource() - device, err := r.FindDeviceAvailable() - if err != nil { - return "", err - } - - report, err := r.GetReport(device, reportData) - if err != nil { - return "", err - } - - return report, nil -} - -func (*measurementServer) GetMeasurement(ctx context.Context, measurementReq *pb.GetMeasurementRequest) (*pb.GetMeasurementReply, error) { - var measurement_type pb.TYPE - var measurement string - var err error - - measurement_type = measurementReq.MeasurementType - - switch measurement_type { - case pb.TYPE_SAAS: - measurement, err = getContainerMeasurement(measurementReq) - case pb.TYPE_PAAS: - measurement, err = getPaasMeasurement(measurementReq) - default: - log.Println("Invalid measurement type.") - return &pb.GetMeasurementReply{}, InvalidRequestErr - - } - - if err != nil { - return &pb.GetMeasurementReply{}, err - } - return &pb.GetMeasurementReply{Measurement: measurement}, nil -} - -func (*measurementServer) Check(ctx context.Context, in *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) { - return &grpc_health_v1.HealthCheckResponse{ - Status: grpc_health_v1.HealthCheckResponse_SERVING, - }, nil -} - -func (*measurementServer) Watch(in *grpc_health_v1.HealthCheckRequest, stream grpc_health_v1.Health_WatchServer) error { - return nil -} - -func newServer() *measurementServer { - s := &measurementServer{} - return s -} - -func main() { - if _, err := os.Stat(sockAddr); !os.IsNotExist(err) { - if err := os.RemoveAll(sockAddr); err != nil { - log.Fatal(err) - } - } - - lis, err := net.Listen(protocol, sockAddr) - if err != nil { - log.Fatalf("failed to listen: %v", err) - } - - opts := []grpc.ServerOption{ - grpc.MaxConcurrentStreams(MAX_CONCURRENT_STREAMS), - } - - grpcServer := grpc.NewServer(opts...) - healthServer := health.NewServer() - - pb.RegisterMeasurementServer(grpcServer, newServer()) - grpc_health_v1.RegisterHealthServer(grpcServer, healthServer) - - log.Printf("server listening at %v", lis.Addr()) - reflection.Register(grpcServer) - if err = grpcServer.Serve(lis); err != nil { - log.Fatalf("failed to serve: %v", err) - } -} diff --git a/service/measurement-server/server/server_test.go b/service/measurement-server/server/server_test.go deleted file mode 100644 index 3b7c10c..0000000 --- a/service/measurement-server/server/server_test.go +++ /dev/null @@ -1,160 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 - */ -package main - -import ( - "context" - "encoding/base64" - "errors" - "log" - "net" - "testing" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/test/bufconn" - - pb "github.com/intel/confidential-cloud-native-primitives/service/measurement-server/proto" -) - -const ( - INVALID_MEASUREMENT_TYPE pb.TYPE = 9 - INVALID_MEASUREMENT_CATEGORY pb.CATEGORY = 9 -) - -var lis *bufconn.Listener - -func initTestServer(ctx context.Context) { - buffer := 1024 * 1024 - lis = bufconn.Listen(buffer) - - server := grpc.NewServer() - pb.RegisterMeasurementServer(server, &measurementServer{}) - go func() { - if err := server.Serve(lis); err != nil { - log.Printf("error serving server: %v", err) - } - }() -} - -func TestMeasurementServerGetMeasurement(t *testing.T) { - ctx := context.Background() - initTestServer(ctx) - - conn, err := grpc.DialContext(ctx, "", grpc.WithContextDialer( - func(context.Context, string) (net.Conn, error) { - return lis.Dial() - }), grpc.WithTransportCredentials(insecure.NewCredentials())) - if err != nil { - log.Printf("failed to connect to server: %v", err) - return - } - defer conn.Close() - client := pb.NewMeasurementClient(conn) - - type expectation struct { - err error - } - - tests := map[string]struct { - in *pb.GetMeasurementRequest - expected expectation - }{ - "Empty_Request": { - in: &pb.GetMeasurementRequest{}, - expected: expectation{ - err: nil, - }, - }, - "Invalid_Measurement_Type": { - in: &pb.GetMeasurementRequest{ - MeasurementType: INVALID_MEASUREMENT_TYPE, - }, - expected: expectation{ - err: errors.New("rpc error: code = Unknown desc = Invalid Request"), - }, - }, - "Invalid_Measurement_Category": { - in: &pb.GetMeasurementRequest{ - MeasurementType: pb.TYPE_PAAS, - MeasurementCategory: INVALID_MEASUREMENT_CATEGORY, - }, - expected: expectation{ - err: errors.New("rpc error: code = Unknown desc = Invalid Request"), - }, - }, - "Request_on_SAAS_Measurement": { - in: &pb.GetMeasurementRequest{ - MeasurementType: pb.TYPE_SAAS, - }, - expected: expectation{ - err: nil, - }, - }, - "Request_on_TPM_Measurement_without_TPM_Support": { - in: &pb.GetMeasurementRequest{ - MeasurementType: pb.TYPE_PAAS, - MeasurementCategory: pb.CATEGORY_TPM, - }, - expected: expectation{ - err: errors.New("rpc error: code = Unknown desc = No applicable device found."), - }, - }, - "Request_on_TEE_Report_Measurement_with_Options_TDX": { - in: &pb.GetMeasurementRequest{ - MeasurementType: pb.TYPE_PAAS, - MeasurementCategory: pb.CATEGORY_TEE_REPORT, - }, - expected: expectation{ - err: nil, - }, - }, - "Request_on_TDX_RTMR_Measurement": { - in: &pb.GetMeasurementRequest{ - MeasurementType: pb.TYPE_PAAS, - MeasurementCategory: pb.CATEGORY_TDX_RTMR, - RegisterIndex: 0, - }, - expected: expectation{ - err: nil, - }, - }, - "Request_on_TDX_Measurement_with_Invalid_Register_Index": { - in: &pb.GetMeasurementRequest{ - MeasurementType: pb.TYPE_PAAS, - MeasurementCategory: pb.CATEGORY_TDX_RTMR, - RegisterIndex: 5, - }, - expected: expectation{ - err: errors.New("rpc error: code = Unknown desc = Invalid RTMR index used."), - }, - }, - } - - for scenario, tt := range tests { - t.Run(scenario, func(t *testing.T) { - out, err := client.GetMeasurement(ctx, tt.in) - if err != nil { - if tt.expected.err == nil { - t.Errorf("Err -> \nWant: nil\nGot: %q\n", err) - } else { - if tt.expected.err.Error() != err.Error() { - t.Errorf("Err -> \nWant: %q\nGot: %q\n", tt.expected.err, err) - } - } - } else { - if tt.in.MeasurementType != pb.TYPE_SAAS && out.Measurement == "" { - t.Errorf("Out -> \nWant measurement\nGot : %q\n", out) - } else { - _, err = base64.StdEncoding.DecodeString(out.Measurement) - if err != nil { - t.Errorf("Out -> \nWant base64 encoded measurement\nGot: %q\n", out.Measurement) - } - } - } - - }) - } -} diff --git a/service/pod-quote/Cargo.toml b/service/pod-quote/Cargo.toml deleted file mode 100644 index 58bbecd..0000000 --- a/service/pod-quote/Cargo.toml +++ /dev/null @@ -1,37 +0,0 @@ -[package] -name = "pod_quote" -version = "0.1.0" -edition = "2021" - -[[bin]] # Bin to run the quote server -name = "pod_quote" -path = "src/pod_quote.rs" - -[dependencies] -tonic = "0.9" -prost = "0.11" -tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } -tokio-stream = "0.1.14" -anyhow = "1.0" -async-trait = "0.1.56" -base64 = "0.13.0" -log = "0.4.14" -serde_json = "1.0" -sha2 = "0.10" -clap = { version = "4.0.29", features = ["derive"] } -tonic-reflection = "0.9.2" -tonic-health = "0.9.2" -nix = "0.26.2" -tdx_attest = "0.1.1" -kube = { version = "0.74.0", features = ["runtime", "derive"] } -k8s-openapi = { version = "0.15.0", features = ["v1_24"] } -crypto-hash = "0.3.3" -async-std = "1.8" -hyper = { version ="0.14.27" } - -[dev-dependencies] -tower = { version = "0.4", features = ["util"] } -serial_test = { version ="2.0.0" } - -[build-dependencies] -tonic-build = "0.9" diff --git a/service/pod-quote/README.md b/service/pod-quote/README.md deleted file mode 100644 index 0f6d42a..0000000 --- a/service/pod-quote/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# Service: CCNP Pod Quote - -This service will provide quote generated by underlying TEE platform for remote attestation service to verify the integrity and confidentiality of the trusted computing environment and required software environment. - -## Introduction - -This server provides functionality to fetch quote of underlying TEE platform with nonce as mandatory input and a base64 encoded user data as optional input.The nonce and user data will be digested and added into quote for remote attestation to verify the freshness of the quote and the user specified data. And it also provides a HTTP REST API for fetching the quote data of current pod which is based on the image IDs of each container in Kubernetes cluster. - -## Installation -The pod quote service can be deployed as a sidecar according to different user scenarios. - -### Prerequisite -User need to have a kubernetes cluster ready to deploy the services. To simplify the deployment process, we provide Helm as one of the options to deploy the service. Please install Helm by following the [Helm official guide](https://helm.sh/docs/intro/install/). However, user can also use the yaml files located in the manifests folder for deployment. -Also, the ccnp device plugin need to installed before the installation of quote server. Please refer to its [deployment guide](../../device-plugin/ccnp-device-plugin/README.md) for installation. - -### Build docker image -The Dockerfile for the service can be found under `container/quote-server` directory. Use the following command to build the image: - -``` -docker build -t ccnp-pod-quote:0.1 -f container/pod-quote/Dockerfile . -``` - -> Note: if you are using containerd as the default runtime for kubernetes, don't forget to use the following commands to import the image into containerd first: -``` -docker save -o ccnp-pod-quote.tar ccnp-pod-quote:0.1 -ctr -n=k8s.io image import ccnp-pod-quote.tar -``` - -### Deploy as DaemonSet in Kubernetes - -#### deploy using manifests yaml file - -please check file `deployment/manifests/pod-quote-deployment.yaml` to confirm the container image to use and run: -``` -kubectl apply -f deployment/manifests/pod-quote-deployment.yaml -``` - -## Testing -You can play with service on host by following the steps below: - -1. Start the pod quote service - -``` -root@tdx-guest:~# ls -l /run/ccnp/ -total 0 -drwxr-xrwx 2 root root 60 Sep 1 05:05 uds -``` - -And then build and run the quote server with binary: -``` -cd service/pod-quote -make build -./target/release/pod-quote -``` -2. Play with the service -Provide a HTTP API for fetching the quote data in `localhost:3000/quote` - -Get quote from the TDX platform: -``` -curl -s http://localhost:3000/quote -``` - -and the output should be as bellow: -``` -{ - "BAACAIEAAAAAAAAAk5pyM/ecTKmUCg2zlX8GB6P8pz1eLkNLuYzlFq7gmQ4AAAAABAAGAAAAAAAAAAAAAAAAAEj6aZSdsIAC7oQlKEf1cpiLHW5WjsE1P2TLbA/ZBTdfaa2VnA6vd0escKOSeJMCoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAADnAgYAAAAAAKSgAzRsWhmm/SUEcehyvQcdjJLXQxq9pGNBeAihc4OqDUKYeBS8kvX1nGBEtnf1FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8sw2a5sIgf6+MgszlJcgpq4sP0tqpfKTspZny2PWPOYiJbt1aPe1rpeqDtoa+NreW8yD5Jj8ypKTGA+WfwPH77+negDf9ZWNeonsxRtNtsLoUabMeutZ+xSCbs5gUWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO+/PqJMpmXxEfoJELnxuPmAbw69VjN9ZQQqe3NjVd72ql13C43JW093ytpa7ipkSR7msIelxHz9nmDTkSucmGPMEAAA0doq0wnfzK1RM8LVMVECwOpiI5ePJkQ7KClggtiBrCrBhE6p3ECY4SUVhWET733tRdTwhkH3JNCkvTIRGeXE3SY1oRIxb7dVmrMVrWdmmfldJoB8RvpN7HOs/g788NOgFoemd5F95mGdNVJ3v0ppPvgJQ5ryby6SOYHAsL25dbkGAEYQAAAGBhMVA/8ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAAAOcAAAAAAAAAOWseNYAkJ5SHxHr5xWG93BUlhjmq0t2vdgCQ70Y/C4QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANyeKnxvlI8XR040p/xD7QMPfBVj8bq932NAyC4OVKjFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOYzIRlhSwSQeVYIlVCCAgcDb+K5pY0hOxqAEm1vN5p/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXrF4+4CGy/IYdLV5k30DF9yMXwa6zYhBz8QproGhnTZPTIEXSIJLkzgEx9OaFrepQWCu+wbggzJVLqv9hg6a5IAAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHwUAXg4AAC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFOERDQ0JKYWdBd0lCQWdJVWR2clZDNnpJTFRvbGI0ZEt5RGhsbFlaUEc1RXdDZ1lJS29aSXpqMEVBd0l3CmNERWlNQ0FHQTFVRUF3d1pTVzUwWld3Z1UwZFlJRkJEU3lCUWJHRjBabTl5YlNCRFFURWFNQmdHQTFVRUNnd1IKU1c1MFpXd2dRMjl5Y0c5eVlYUnBiMjR4RkRBU0JnTlZCQWNNQzFOaGJuUmhJRU5zWVhKaE1Rc3dDUVlEVlFRSQpEQUpEUVRFTE1Ba0dBMVVFQmhNQ1ZWTXdIaGNOTWpNd05URTJNRGd5TXpJd1doY05NekF3TlRFMk1EZ3lNekl3CldqQndNU0l3SUFZRFZRUUREQmxKYm5SbGJDQlRSMWdnVUVOTElFTmxjblJwWm1sallYUmxNUm93R0FZRFZRUUsKREJGSmJuUmxiQ0JEYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRnVkR0VnUTJ4aGNtRXhDekFKQmdOVgpCQWdNQWtOQk1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCUHZQClNtKzJtU1R2TzE0RkhpOXd3K05qYUhzazhyVHFQQ0xEMDZ3MmtJVE9yb0RYSmN5NDBMbHRZemFBZ3JXR2FsWFoKTy9GY3cxc0padDZZdFNRVHlyU2pnZ01NTUlJRENEQWZCZ05WSFNNRUdEQVdnQlNWYjEzTnZSdmg2VUJKeWRUMApNODRCVnd2ZVZEQnJCZ05WSFI4RVpEQmlNR0NnWHFCY2hscG9kSFJ3Y3pvdkwyRndhUzUwY25WemRHVmtjMlZ5CmRtbGpaWE11YVc1MFpXd3VZMjl0TDNObmVDOWpaWEowYVdacFkyRjBhVzl1TDNZMEwzQmphMk55YkQ5allUMXcKYkdGMFptOXliU1psYm1OdlpHbHVaejFrWlhJd0hRWURWUjBPQkJZRUZEUGs4eit4L0JtVkw5UDVJTkRaNlhlUwpTOHR4TUE0R0ExVWREd0VCL3dRRUF3SUd3REFNQmdOVkhSTUJBZjhFQWpBQU1JSUNPUVlKS29aSWh2aE5BUTBCCkJJSUNLakNDQWlZd0hnWUtLb1pJaHZoTkFRMEJBUVFRUGYyUXdCNHRTYzhyRmxvZGJJQzlCVENDQVdNR0NpcUcKU0liNFRRRU5BUUl3Z2dGVE1CQUdDeXFHU0liNFRRRU5BUUlCQWdFRk1CQUdDeXFHU0liNFRRRU5BUUlDQWdFRgpNQkFHQ3lxR1NJYjRUUUVOQVFJREFnRUNNQkFHQ3lxR1NJYjRUUUVOQVFJRUFnRUNNQkFHQ3lxR1NJYjRUUUVOCkFRSUZBZ0VETUJBR0N5cUdTSWI0VFFFTkFRSUdBZ0VCTUJBR0N5cUdTSWI0VFFFTkFRSUhBZ0VBTUJBR0N5cUcKU0liNFRRRU5BUUlJQWdFRE1CQUdDeXFHU0liNFRRRU5BUUlKQWdFQU1CQUdDeXFHU0liNFRRRU5BUUlLQWdFQQpNQkFHQ3lxR1NJYjRUUUVOQVFJTEFnRUFNQkFHQ3lxR1NJYjRUUUVOQVFJTUFnRUFNQkFHQ3lxR1NJYjRUUUVOCkFRSU5BZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSU9BZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSVBBZ0VBTUJBR0N5cUcKU0liNFRRRU5BUUlRQWdFQU1CQUdDeXFHU0liNFRRRU5BUUlSQWdFTE1COEdDeXFHU0liNFRRRU5BUUlTQkJBRgpCUUlDQXdFQUF3QUFBQUFBQUFBQU1CQUdDaXFHU0liNFRRRU5BUU1FQWdBQU1CUUdDaXFHU0liNFRRRU5BUVFFCkJnQ0Fid1VBQURBUEJnb3Foa2lHK0UwQkRRRUZDZ0VCTUI0R0NpcUdTSWI0VFFFTkFRWUVFQUxFbzJLdDd4d3QKNmhQZGdZekRNMFl3UkFZS0tvWklodmhOQVEwQkJ6QTJNQkFHQ3lxR1NJYjRUUUVOQVFjQkFRSC9NQkFHQ3lxRwpTSWI0VFFFTkFRY0NBUUVBTUJBR0N5cUdTSWI0VFFFTkFRY0RBUUgvTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDCklBTURNUDNSaUJOYVpuM2NLUjducFVxNDFkTm1HNzIzZlFYcWlJVTU0U09KQWlFQSsrZW9Ta1ZOa2NnbERLZncKaDNDbGx6UzNway9hSGhYNjZDUjc1TllJanpnPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDbGpDQ0FqMmdBd0lCQWdJVkFKVnZYYzI5RytIcFFFbkoxUFF6emdGWEM5NVVNQW9HQ0NxR1NNNDlCQU1DCk1HZ3hHakFZQmdOVkJBTU1FVWx1ZEdWc0lGTkhXQ0JTYjI5MElFTkJNUm93R0FZRFZRUUtEQkZKYm5SbGJDQkQKYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRnVkR0VnUTJ4aGNtRXhDekFKQmdOVkJBZ01Ba05CTVFzdwpDUVlEVlFRR0V3SlZVekFlRncweE9EQTFNakV4TURVd01UQmFGdzB6TXpBMU1qRXhNRFV3TVRCYU1IQXhJakFnCkJnTlZCQU1NR1VsdWRHVnNJRk5IV0NCUVEwc2dVR3hoZEdadmNtMGdRMEV4R2pBWUJnTlZCQW9NRVVsdWRHVnMKSUVOdmNuQnZjbUYwYVc5dU1SUXdFZ1lEVlFRSERBdFRZVzUwWVNCRGJHRnlZVEVMTUFrR0ExVUVDQXdDUTBFeApDekFKQmdOVkJBWVRBbFZUTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFTlNCLzd0MjFsWFNPCjJDdXpweHc3NGVKQjcyRXlER2dXNXJYQ3R4MnRWVExxNmhLazZ6K1VpUlpDbnFSN3BzT3ZncUZlU3hsbVRsSmwKZVRtaTJXWXozcU9CdXpDQnVEQWZCZ05WSFNNRUdEQVdnQlFpWlF6V1dwMDBpZk9EdEpWU3YxQWJPU2NHckRCUwpCZ05WSFI4RVN6QkpNRWVnUmFCRGhrRm9kSFJ3Y3pvdkwyTmxjblJwWm1sallYUmxjeTUwY25WemRHVmtjMlZ5CmRtbGpaWE11YVc1MFpXd3VZMjl0TDBsdWRHVnNVMGRZVW05dmRFTkJMbVJsY2pBZEJnTlZIUTRFRmdRVWxXOWQKemIwYjRlbEFTY25VOURQT0FWY0wzbFF3RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJTUFZQgpBZjhDQVFBd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1hzVmtpMHcraTZWWUdXM1VGLzIydWFYZTBZSkRqMVVlCm5BK1RqRDFhaTVjQ0lDWWIxU0FtRDV4a2ZUVnB2bzRVb3lpU1l4ckRXTG1VUjRDSTlOS3lmUE4rCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNqekNDQWpTZ0F3SUJBZ0lVSW1VTTFscWROSW56ZzdTVlVyOVFHemtuQnF3d0NnWUlLb1pJemowRUF3SXcKYURFYU1CZ0dBMVVFQXd3UlNXNTBaV3dnVTBkWUlGSnZiM1FnUTBFeEdqQVlCZ05WQkFvTUVVbHVkR1ZzSUVOdgpjbkJ2Y21GMGFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQkRiR0Z5WVRFTE1Ba0dBMVVFQ0F3Q1EwRXhDekFKCkJnTlZCQVlUQWxWVE1CNFhEVEU0TURVeU1URXdORFV4TUZvWERUUTVNVEl6TVRJek5UazFPVm93YURFYU1CZ0cKQTFVRUF3d1JTVzUwWld3Z1UwZFlJRkp2YjNRZ1EwRXhHakFZQmdOVkJBb01FVWx1ZEdWc0lFTnZjbkJ2Y21GMAphVzl1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRUNBd0NRMEV4Q3pBSkJnTlZCQVlUCkFsVlRNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVDNm5Fd01ESVlaT2ovaVBXc0N6YUVLaTcKMU9pT1NMUkZoV0dqYm5CVkpmVm5rWTR1M0lqa0RZWUwwTXhPNG1xc3lZamxCYWxUVll4RlAyc0pCSzV6bEtPQgp1ekNCdURBZkJnTlZIU01FR0RBV2dCUWlaUXpXV3AwMGlmT0R0SlZTdjFBYk9TY0dyREJTQmdOVkhSOEVTekJKCk1FZWdSYUJEaGtGb2RIUndjem92TDJObGNuUnBabWxqWVhSbGN5NTBjblZ6ZEdWa2MyVnlkbWxqWlhNdWFXNTAKWld3dVkyOXRMMGx1ZEdWc1UwZFlVbTl2ZEVOQkxtUmxjakFkQmdOVkhRNEVGZ1FVSW1VTTFscWROSW56ZzdTVgpVcjlRR3prbkJxd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRRXdDZ1lJCktvWkl6ajBFQXdJRFNRQXdSZ0loQU9XLzVRa1IrUzlDaVNEY05vb3dMdVBSTHNXR2YvWWk3R1NYOTRCZ3dUd2cKQWlFQTRKMGxySG9NcytYbzVvL3NYNk85UVd4SFJBdlpVR09kUlE3Y3ZxUlhhcUk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KAA==" -} -``` diff --git a/service/pod-quote/deny.toml b/service/pod-quote/deny.toml deleted file mode 100644 index 6e656f7..0000000 --- a/service/pod-quote/deny.toml +++ /dev/null @@ -1,35 +0,0 @@ -[advisories] -vulnerability = "deny" -unmaintained = "warn" -yanked = "warn" -notice = "warn" - -[licenses] -unlicensed = "warn" -allow = [ - "MIT", - "Apache-2.0", - "ISC", - "BSD-3-Clause", - "Unicode-DFS-2016", -] - -copyleft = "warn" -allow-osi-fsf-free = "neither" -default = "deny" -confidence-threshold = 0.8 - -[[licenses.clarify]] -name = "ring" -expression = "MIT AND ISC AND OpenSSL" -license-files = [ - { path = "LICENSE", hash = 0xbd0eed23 } -] - -[bans] -multiple-versions = "warn" -wildcards = "allow" - -[sources] -unknown-registry = "warn" -unknown-git = "warn" \ No newline at end of file diff --git a/service/pod-quote/src/kube.rs b/service/pod-quote/src/kube.rs deleted file mode 100644 index 83bc0d1..0000000 --- a/service/pod-quote/src/kube.rs +++ /dev/null @@ -1,60 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 -*/ - -extern crate crypto_hash; -extern crate kube; - -use anyhow::{anyhow, Error}; -use k8s_openapi::api::core::v1::Pod; -use kube::api::Api; -use kube::Client; - -use std::env; - -const POD_NAME: &str = "POD_NAME"; -const POD_NAMESPACE: &str = "POD_NAMESPACE"; -const SEPARATOR: &str = "|"; - -pub async fn get_cur_pod_images_info() -> Result { - let mut pod_data_array: Vec = Vec::new(); - let namespace = env::var(POD_NAMESPACE).unwrap_or_default(); - let pod_name = env::var(POD_NAME).unwrap_or_default(); - - let client = Client::try_default().await?; - let pods: Api = Api::namespaced(client.clone(), &namespace); - - let pod_name_str = pod_name.clone(); - let cur_pod = pods.get(&pod_name_str).await?; - // Access the container statuses - if let Some(status) = cur_pod.status { - for container_status in status.container_statuses.unwrap_or_default() { - let image_id = container_status.image_id.clone(); - pod_data_array.push(image_id); - } - println!("pod quote data array:"); - // Print out the quote data of pod. - for item in &pod_data_array { - println!("{}", item); - } - - // Concat all pod quote data into one String. - let pod_image_id_data = pod_data_array.join(SEPARATOR); - return Ok(pod_image_id_data); - } else { - println!("Pod {pod_name} in {namespace} not found."); - let error_message = format!("Pod '{}' in '{}' not found.", pod_name, namespace); - return Err(anyhow!(error_message)); - } -} - -pub fn sha256_hash(input: &str) -> String { - // Convert the input string to bytes - let input_bytes = input.as_bytes(); - - // Calculate the SHA-256 hash - let hash = crypto_hash::hex_digest(crypto_hash::Algorithm::SHA256, input_bytes); - - hash -} diff --git a/service/pod-quote/src/pod_quote.rs b/service/pod-quote/src/pod_quote.rs deleted file mode 100644 index 2d0de1a..0000000 --- a/service/pod-quote/src/pod_quote.rs +++ /dev/null @@ -1,129 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 -*/ - -use anyhow::*; -use clap::Parser; -use core::result::Result::Ok; -use hyper::service::{make_service_fn, service_fn}; -use hyper::{Request as HyperRequest, Response as HyperResponse, Body, Server as HyperServer}; -use std::net::SocketAddr; - -pub mod kube; -pub mod tee; -use tee::*; - -// A http server for provide the current pod quote data -#[derive(Copy, Clone)] -pub struct PerPodQuoteServer { - sock_address: SocketAddr, - local_tee: tee::TeeType, -} - -impl PerPodQuoteServer { - pub fn new(sock_address: SocketAddr, local_tee: tee::TeeType) -> Self { - PerPodQuoteServer { - sock_address, - local_tee, - } - } - - pub async fn start(&self) -> Result<(), hyper::Error> { - let local_tee = self.local_tee; - let make_svc = make_service_fn(|_conn| { - let service = service_fn(move |req| { - // Route request to the appropriate handler - Self::handle_request(local_tee, req) - }); - async move { Ok::<_, hyper::Error>(service) } - }); - let http_server = HyperServer::bind(&self.sock_address).serve(make_svc); - println!( - "The Pod Quote HTTP server is listening on: {:?}", - self.sock_address - ); - http_server.await - } - - // generate current pod quote based on its all containers' imageIDs - async fn get_current_pod_quote(local_tee: tee::TeeType) -> Result { - // Handle the "/quote" route - // Create an instance of your custom kube client - let pod_data = kube::get_cur_pod_images_info(); - match pod_data.await { - Ok(report_data) => { - let report_data_clone = report_data.clone(); - let hash_report_data = kube::sha256_hash(&report_data_clone); - let quote_data = get_quote( - local_tee, - hash_report_data.clone(), - hash_report_data.clone(), - ) - .unwrap(); - Ok(quote_data) - } - Err(error) => Err(anyhow!( - "There was a problem when get current pod images information: {:?}", - error - )), - } - } - - async fn handle_request( - local_tee: tee::TeeType, - req: HyperRequest - ) -> Result, hyper::Error> { - match req.uri().path() { - "/quote" => { - match Self::get_current_pod_quote(local_tee).await { - Ok(quote_data) => { - println!("File content: {}", quote_data); - // generate the response from quote file - let response = HyperResponse::new(Body::from(quote_data)); - Ok(response) - } - Err(err) => { - eprintln!("Error: {}", err); - let response = HyperResponse::builder() - .status(404) - .body(Body::from("Not Found Quote File")) - .unwrap(); - Ok(response) - } - } - } - _ => { - // Handle other routes - let response = HyperResponse::builder() - .status(404) - .body(Body::from("Not Found")) - .unwrap(); - Ok(response) - } - } - } -} - -#[derive(Parser)] -struct Cli { - port: String, -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - let http_addr = SocketAddr::from(([127, 0, 0, 1], 3000)); - // Create the http server tokio task for fetching quote with current pod image IDs - let _ = tokio::spawn(async move { - let http_server = PerPodQuoteServer::new(http_addr, { - match tee::get_tee_type() { - tee::TeeType::PLAIN => panic!("Not found any TEE device!"), - t => t, - } - }); - if let Err(err) = http_server.start().await { - eprintln!("HTTP server error: {}", err); - } - }); - Ok(()) -} diff --git a/service/pod-quote/src/tee.rs b/service/pod-quote/src/tee.rs deleted file mode 100644 index b05743c..0000000 --- a/service/pod-quote/src/tee.rs +++ /dev/null @@ -1,425 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 -*/ - -use anyhow::*; -use sha2::{Digest, Sha512}; -use std::path::Path; -use std::result::Result::Ok; - -#[derive(Debug, Copy, Clone)] -pub enum TeeType { - TDX, - SEV, - TPM, - PLAIN, -} - -pub fn get_tee_type() -> TeeType { - if Path::new("/dev/tpm0").exists() { - TeeType::TPM - } else if Path::new("/dev/tdx-guest").exists() - || Path::new("/dev/tdx-attest").exists() - || Path::new("/dev/tdx_guest").exists() - { - if Path::new("/dev/tdx-attest").exists() { - panic!("[get_tee_type]: Deprecated device node /dev/tdx-attest, please upgrade to use /dev/tdx-guest or /dev/tdx_guest"); - } - TeeType::TDX - } else if Path::new("/dev/sev-guest").exists() || Path::new("/dev/sev").exists() { - TeeType::SEV - } else { - TeeType::PLAIN - } -} - -fn generate_tdx_report_data( - report_data: Option, - nonce: String, -) -> Result { - let nonce_decoded = match base64::decode(nonce) { - Ok(v) => v, - Err(e) => { - return Err(anyhow!( - "[generate_tdx_report_data] nonce is not base64 encoded: {:?}", - e - )) - } - }; - let mut hasher = Sha512::new(); - hasher.update(nonce_decoded); - let _ret = match report_data { - Some(_encoded_report_data) => { - if _encoded_report_data.is_empty() { - hasher.update("") - } else { - let decoded_report_data = match base64::decode(_encoded_report_data) { - Ok(v) => v, - Err(e) => { - return Err(anyhow!( - "[generate_tdx_report_data] user data is not base64 encoded: {:?}", - e - )) - } - }; - hasher.update(decoded_report_data) - } - } - None => hasher.update(""), - }; - let hash_array: [u8; 64] = hasher - .finalize() - .as_slice() - .try_into() - .expect("[generate_tdx_report_data] Wrong length of report data"); - Ok(base64::encode(hash_array)) -} - -fn get_tdx_quote(report_data: Option, nonce: String) -> Result { - let tdx_report_data = match generate_tdx_report_data(report_data, nonce) { - Ok(v) => v, - Err(e) => { - return Err(anyhow!("[get_tdx_quote]: {:?}", e)); - } - }; - - let quote = match tdx_attest::get_tdx_quote(tdx_report_data) { - Err(e) => panic!("[get_tdx_quote] Fail to get TDX quote: {:?}", e), - Ok(q) => base64::encode(q), - }; - - serde_json::to_string("e).map_err(|e| anyhow!("[get_tdx_quote]: {:?}", e)) -} - -fn get_tpm_quote() -> Result { - Err(anyhow!("TPM to be supported!")) -} - -fn get_sev_quote() -> Result { - Err(anyhow!("SEV to be supported!")) -} - -pub fn get_quote(local_tee: TeeType, user_data: String, nonce: String) -> Result { - match local_tee { - TeeType::TDX => get_tdx_quote(Some(user_data), nonce), - TeeType::TPM => get_tpm_quote(), - TeeType::SEV => get_sev_quote(), - _ => Err(anyhow!("Unexpected case!")), - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - //generate_tdx_report allow empty nonce - fn generate_tdx_report_data_empty_nonce() { - let result = generate_tdx_report_data(Some("YWJjZGVmZw==".to_string()), "".to_string()); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow optional report data - fn tdx_get_quote_report_data_no_report_data() { - let result = generate_tdx_report_data(None, "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow empty report data string - fn generate_tdx_report_data_report_data_size_0() { - let result = - generate_tdx_report_data(Some("".to_string()), "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow 8 bytes report data string - fn generate_tdx_report_data_report_data_size_8() { - let result = generate_tdx_report_data( - Some("YWJjZGVmZw==".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow 48 bytes report data string - fn generate_tdx_report_data_size_report_data_size_48() { - // this one should be standard 48 bytes base64 encoded report data - // "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4" is base64 of "123456781234567812345678123456781234567812345678", 48 bytes - let result = generate_tdx_report_data( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report require report data string is base64 encoded - fn generate_tdx_report_data_report_data_not_base64_encoded() { - //coming in report data should always be base64 encoded - let result = generate_tdx_report_data( - Some("XD^%*!x".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //generate_tdx_report require nonce string is base64 encoded - fn generate_tdx_report_data_nonce_not_base64_encoded() { - //coming in nonce should always be base64 encoded - let result = generate_tdx_report_data( - Some("IXUKoBO1XEFBPwopN4sY".to_string()), - "XD^%*!x".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //generate_tdx_report require nonce string is base64 encoded - fn generate_tdx_report_data_nonce_short_not_base64_encoded() { - //coming in nonce should always be base64 encoded - let result = - generate_tdx_report_data(Some("IXUKoBO1XEFBPwopN4sY".to_string()), "123".to_string()); - assert!(result.is_err()); - } - - #[test] - //generate_tdx_report require report data string is base64 encoded - fn generate_tdx_report_data_report_data_short_not_base64_encoded() { - //coming in report data should always be base64 encoded - let result = - generate_tdx_report_data(Some("123".to_string()), "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_err()); - } - - #[test] - //generate_tdx_report check result as expected - //original report_data = "abcdefgh", orginal nonce = "12345678" - fn generate_tdx_report_data_report_data_nonce_base64_encoded_as_expected() { - let result = - generate_tdx_report_data(Some("YWJjZGVmZw==".to_string()), "MTIzNDU2Nzg=".to_string()) - .unwrap(); - let expected_hash = [ - 93, 71, 28, 83, 115, 189, 166, 130, 87, 137, 126, 119, 140, 209, 163, 215, 13, 175, - 225, 101, 64, 195, 196, 202, 15, 37, 166, 241, 141, 49, 128, 157, 164, 132, 67, 50, 9, - 32, 162, 89, 243, 191, 177, 131, 4, 159, 156, 104, 11, 193, 18, 217, 92, 215, 194, 98, - 145, 191, 211, 85, 187, 118, 39, 80, - ]; - let generated_hash = base64::decode(result).unwrap(); - assert_eq!(generated_hash, expected_hash); - } - - #[test] - //generate_tdx_report allow long report data string - fn generate_tdx_report_data_long_tdx_report_data() { - let result = generate_tdx_report_data( - Some( - "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzgx\ - MjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEy\ - MzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIz\ - NDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0\ - NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1\ - Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2\ - NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4Cg==" - .to_string(), - ), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow long nonce string - fn generate_tdx_report_data_long_nonce() { - let result = generate_tdx_report_data( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzgx\ - MjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEy\ - MzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIz\ - NDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0\ - NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1\ - Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2\ - NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4Cg==" - .to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report_data generated report data is 64 bytes - fn generate_tdx_report_data_report_data_is_64_bytes() { - let report_data_hashed = match generate_tdx_report_data( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ) { - Ok(r) => r, - Err(_) => todo!(), - }; - let generated_hash_len = base64::decode(report_data_hashed).unwrap().len(); - assert_eq!(generated_hash_len, 64); - } - - #[test] - //TDX ENV required: tdx_get_quote allow empty nonce - fn tdx_get_quote_empty_nonce() { - let result = get_tdx_quote(Some("YWJjZGVmZw==".to_string()), "".to_string()); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow 0 bytes report data string - fn tdx_get_quote_report_data_size_0() { - let result = get_tdx_quote(Some("".to_string()), "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow 8 bytes report data string - fn tdx_get_quote_report_data_size_8() { - // "YWJjZGVmZw==" is base64 of "abcdefg", 8 bytes - let result = get_tdx_quote( - Some("YWJjZGVmZw==".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow 48 bytes report data string - fn tdx_get_quote_report_data_size_48() { - let result = get_tdx_quote( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow optional report data - fn tdx_get_quote_report_data_null() { - let result = get_tdx_quote(None, "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote require report data string is base64 encoded - fn tdx_get_quote_report_data_not_base64_encoded() { - let result = get_tdx_quote( - Some("XD^%*!x".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //TDX ENV required: tdx_get_quote require nonce string is base64 encoded - fn tdx_get_quote_nonce_not_base64_encoded() { - let result = get_tdx_quote( - Some("IXUKoBO1XEFBPwopN4sY".to_string()), - "XD^%*!x".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow long report data string - fn tdx_get_quote_long_tdx_report_data() { - let result = get_tdx_quote( - Some( - "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzgx\ - MjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEy\ - MzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIz\ - NDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0\ - NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1\ - Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2\ - NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4Cg==" - .to_string(), - ), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow long nonce string - fn tdx_get_quote_long_nonce() { - let result = get_tdx_quote( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzgx\ - MjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEy\ - MzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIz\ - NDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0\ - NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1\ - Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2\ - NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4Cg==" - .to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: get_tdx_quote return non-empty encoded quote string - fn tdx_get_quote_report_data_encoded_quote_is_not_0_bytes() { - let quote = match get_tdx_quote( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ) { - Ok(r) => r, - Err(_) => todo!(), - }; - assert_ne!(quote.len(), 0); - } - - #[test] - //get_quote does not allow tee type beyond TDX/SEV/TPM - fn get_quote_wrong_tee_type() { - let result = get_quote( - TeeType::PLAIN, - "".to_string(), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //get_quote does not support SEV for now - fn get_quote_sev_tee_type() { - //does not allow tee type beyond TDX/SEV/TPM - let result = get_quote( - TeeType::SEV, - "".to_string(), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //get_quote does not support TPM for now - fn get_quote_tpm_tee_type() { - //does not allow tee type beyond TDX/SEV/TPM - let result = get_quote( - TeeType::TPM, - "".to_string(), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //get_quote support TDX now - fn get_quote_tdx_tee_type() { - //does not allow tee type beyond TDX/SEV/TPM - let result = get_quote( - TeeType::TDX, - "".to_string(), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } -} diff --git a/service/pod-quote/tdx_attest/Cargo.toml b/service/pod-quote/tdx_attest/Cargo.toml deleted file mode 100644 index d543db9..0000000 --- a/service/pod-quote/tdx_attest/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "tdx_attest" -version = "0.1.1" -edition = "2021" -authors = ["Hairong Chen "] -description = "A rust crate to retrieve TD Report and TDX quote via ioctl" -readme = "README.md" -license = "Apache-2.0" -repository = "https://github.com/confidential-cloud-native-primitives" - -[lib] -name = "tdx_attest" -path = "src/tdx_attest.rs" - -[dependencies] -nix = "0.26.2" -base64 = "0.13.0" -anyhow = "1.0" \ No newline at end of file diff --git a/service/pod-quote/tdx_attest/README.md b/service/pod-quote/tdx_attest/README.md deleted file mode 100644 index 26aba20..0000000 --- a/service/pod-quote/tdx_attest/README.md +++ /dev/null @@ -1 +0,0 @@ -A rust crate to retrieve TD Report and TDX quote via ioctl \ No newline at end of file diff --git a/service/pod-quote/tdx_attest/src/tdx_attest.rs b/service/pod-quote/tdx_attest/src/tdx_attest.rs deleted file mode 100644 index 3420c71..0000000 --- a/service/pod-quote/tdx_attest/src/tdx_attest.rs +++ /dev/null @@ -1,453 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 -*/ - -#![allow(non_camel_case_types)] - -use anyhow::*; -use nix::*; -use std::convert::TryInto; -use std::fs::File; -use std::mem; -use std::os::unix::io::AsRawFd; -use std::path::Path; -use std::ptr; -use std::result::Result; -use std::result::Result::Ok; - -#[repr(C)] -pub struct tdx_1_0_report_req { - subtype: u8, // Subtype of TDREPORT: fixed as 0 by TDX Module specification - reportdata: u64, // User-defined REPORTDATA to be included into TDREPORT - rpd_len: u32, // Length of the REPORTDATA: fixed as 64 bytes by the TDX Module specification - tdreport: u64, // TDREPORT output from TDCALL[TDG.MR.REPORT] - tdr_len: u32, // Length of the TDREPORT: fixed as 1024 bytes by the TDX Module specification -} - -#[repr(C)] -pub struct tdx_1_5_report_req { - reportdata: [u8; REPORT_DATA_LEN as usize], // User buffer with REPORTDATA to be included into TDREPORT - tdreport: [u8; TDX_REPORT_LEN as usize], // User buffer to store TDREPORT output from TDCALL[TDG.MR.REPORT] -} - -#[repr(C)] -pub struct qgs_msg_header { - major_version: u16, // TDX major version - minor_version: u16, // TDX minor version - msg_type: u32, // GET_QUOTE_REQ or GET_QUOTE_RESP - size: u32, // size of the whole message, include this header, in byte - error_code: u32, // used in response only -} - -#[repr(C)] -pub struct qgs_msg_get_quote_req { - header: qgs_msg_header, // header.type = GET_QUOTE_REQ - report_size: u32, // cannot be 0 - id_list_size: u32, // length of id_list, in byte, can be 0 - report_id_list: [u8; TDX_REPORT_LEN as usize], // report followed by id list -} - -#[repr(C)] -pub struct tdx_quote_hdr { - version: u64, // Quote version, filled by TD - status: u64, // Status code of Quote request, filled by VMM - in_len: u32, // Length of TDREPORT, filled by TD - out_len: u32, // Length of Quote, filled by VMM - data_len_be_bytes: [u8; 4], // big-endian 4 bytes indicate the size of data following - data: [u8; TDX_QUOTE_LEN as usize], // Actual Quote data or TDREPORT on input -} - -#[repr(C)] -pub struct tdx_quote_req { - buf: u64, // Pass user data that includes TDREPORT as input. Upon successful completion of IOCTL, output is copied back to the same buffer - len: u64, // Length of the Quote buffer -} - -#[repr(C)] -pub struct qgs_msg_get_quote_resp { - header: qgs_msg_header, // header.type = GET_QUOTE_RESP - selected_id_size: u32, // can be 0 in case only one id is sent in request - quote_size: u32, // length of quote_data, in byte - id_quote: [u8; TDX_QUOTE_LEN], // selected id followed by quote -} - -pub enum TdxVersion { - TDX_1_0, - TDX_1_5, -} - -pub enum TdxOperation { - TDX_GET_TD_REPORT = 1, - TDX_1_0_GET_QUOTE = 2, - TDX_1_5_GET_QUOTE = 4, -} - -const REPORT_DATA_LEN: u32 = 64; -const TDX_REPORT_LEN: u32 = 1024; -const TDX_QUOTE_LEN: usize = 4 * 4096; - -pub struct TdxInfo { - tdx_version: TdxVersion, - device_node: File, -} - -impl TdxInfo { - fn new(_tdx_version: TdxVersion, _device_node: File) -> Self { - TdxInfo { - tdx_version: _tdx_version, - device_node: _device_node, - } - } -} - -fn get_tdx_version() -> TdxVersion { - if Path::new("/dev/tdx-guest").exists() { - TdxVersion::TDX_1_0 - } else if Path::new("/dev/tdx_guest").exists() { - TdxVersion::TDX_1_5 - } else if Path::new("/dev/tdx-attest").exists() { - panic!("get_tdx_version: Deprecated device node /dev/tdx-attest, please upgrade to use /dev/tdx-guest or /dev/tdx_guest"); - } else { - panic!("get_tdx_version: no TDX device found!"); - } -} - -pub fn get_td_report(report_data: String) -> Result, anyhow::Error> { - //detect TDX version - let tdx_info = match get_tdx_version() { - TdxVersion::TDX_1_0 => { - let device_node = match File::options() - .read(true) - .write(true) - .open("/dev/tdx-guest") - { - Err(e) => { - return Err(anyhow!( - "[get_td_report] Fail to open {}: {:?}", - "/dev/tdx-guest", - e - )) - } - Ok(fd) => fd, - }; - TdxInfo::new(TdxVersion::TDX_1_0, device_node) - } - TdxVersion::TDX_1_5 => { - let device_node = match File::options() - .read(true) - .write(true) - .open("/dev/tdx_guest") - { - Err(e) => { - return Err(anyhow!( - "[get_td_report] Fail to open {}: {:?}", - "/dev/tdx_guest", - e - )) - } - Ok(fd) => fd, - }; - TdxInfo::new(TdxVersion::TDX_1_5, device_node) - } - }; - - match tdx_info.tdx_version { - TdxVersion::TDX_1_0 => match get_tdx_1_0_report(tdx_info.device_node, report_data) { - Err(e) => return Err(anyhow!("[get_td_report] Fail to get TDX report: {:?}", e)), - Ok(report) => Ok(report), - }, - TdxVersion::TDX_1_5 => match get_tdx_1_5_report(tdx_info.device_node, report_data) { - Err(e) => return Err(anyhow!("[get_td_report] Fail to get TDX report: {:?}", e)), - Ok(report) => Ok(report), - }, - } -} - -fn get_tdx_1_0_report(device_node: File, report_data: String) -> Result, anyhow::Error> { - let report_data_bytes = match base64::decode(report_data) { - Ok(v) => v, - Err(e) => return Err(anyhow!("report data is not base64 encoded: {:?}", e)), - }; - - //prepare get TDX report request data - let mut report_data_array: [u8; REPORT_DATA_LEN as usize] = [0; REPORT_DATA_LEN as usize]; - report_data_array.copy_from_slice(&report_data_bytes[0..]); - let td_report: [u8; TDX_REPORT_LEN as usize] = [0; TDX_REPORT_LEN as usize]; - - //build the request - let request = tdx_1_0_report_req { - subtype: 0 as u8, - reportdata: ptr::addr_of!(report_data_array) as u64, - rpd_len: REPORT_DATA_LEN, - tdreport: ptr::addr_of!(td_report) as u64, - tdr_len: TDX_REPORT_LEN, - }; - - //build the operator code - ioctl_readwrite!( - get_report_1_0_ioctl, - b'T', - TdxOperation::TDX_GET_TD_REPORT, - u64 - ); - - //apply the ioctl command - match unsafe { - get_report_1_0_ioctl(device_node.as_raw_fd(), ptr::addr_of!(request) as *mut u64) - } { - Err(e) => { - return Err(anyhow!( - "[get_tdx_1_0_report] Fail to get TDX report: {:?}", - e - )) - } - Ok(_) => (), - }; - - Ok(td_report.to_vec()) -} - -fn get_tdx_1_5_report(device_node: File, report_data: String) -> Result, anyhow::Error> { - let report_data_bytes = match base64::decode(report_data) { - Ok(v) => v, - Err(e) => return Err(anyhow!("report data is not base64 encoded: {:?}", e)), - }; - - //prepare get TDX report request data - let mut request = tdx_1_5_report_req { - reportdata: [0; REPORT_DATA_LEN as usize], - tdreport: [0; TDX_REPORT_LEN as usize], - }; - request.reportdata.copy_from_slice(&report_data_bytes[0..]); - - //build the operator code - ioctl_readwrite!( - get_report_1_5_ioctl, - b'T', - TdxOperation::TDX_GET_TD_REPORT, - tdx_1_5_report_req - ); - - //apply the ioctl command - match unsafe { - get_report_1_5_ioctl( - device_node.as_raw_fd(), - ptr::addr_of!(request) as *mut tdx_1_5_report_req, - ) - } { - Err(e) => { - return Err(anyhow!( - "[get_tdx_1_5_report] Fail to get TDX report: {:?}", - e - )) - } - Ok(_) => (), - }; - - Ok(request.tdreport.to_vec()) -} - -fn generate_qgs_quote_msg(report: [u8; TDX_REPORT_LEN as usize]) -> qgs_msg_get_quote_req { - //build quote service message header to be used by QGS - let qgs_header = qgs_msg_header { - major_version: 1, - minor_version: 0, - msg_type: 0, - size: 16 + 8 + TDX_REPORT_LEN, // header + report_size and id_list_size + TDX_REPORT_LEN - error_code: 0, - }; - - //build quote service message body to be used by QGS - let mut qgs_request = qgs_msg_get_quote_req { - header: qgs_header, - report_size: TDX_REPORT_LEN, - id_list_size: 0, - report_id_list: [0; TDX_REPORT_LEN as usize], - }; - - qgs_request.report_id_list.copy_from_slice(&report[0..]); - - qgs_request -} - -pub fn get_tdx_quote(report_data: String) -> Result, anyhow::Error> { - //retrieve TDX report - let report_data_vec = match get_td_report(report_data) { - Err(e) => return Err(anyhow!("[get_tdx_quote] Fail to get TDX report: {:?}", e)), - Ok(report) => report, - }; - let report_data_array: [u8; TDX_REPORT_LEN as usize] = match report_data_vec.try_into() { - Ok(r) => r, - Err(e) => return Err(anyhow!("[get_tdx_quote] Wrong TDX report format: {:?}", e)), - }; - - //build QGS request message - let qgs_msg = generate_qgs_quote_msg(report_data_array); - - let tdx_info = match get_tdx_version() { - TdxVersion::TDX_1_0 => { - let device_node = match File::options() - .read(true) - .write(true) - .open("/dev/tdx-guest") - { - Err(e) => { - return Err(anyhow!( - "[get_tdx_quote] Fail to open {}: {:?}", - "/dev/tdx-guest", - e - )) - } - Ok(fd) => fd, - }; - TdxInfo::new(TdxVersion::TDX_1_0, device_node) - } - TdxVersion::TDX_1_5 => { - let device_node = match File::options() - .read(true) - .write(true) - .open("/dev/tdx_guest") - { - Err(e) => { - return Err(anyhow!( - "[get_tdx_quote] Fail to open {}: {:?}", - "/dev/tdx_guest", - e - )) - } - Ok(fd) => fd, - }; - TdxInfo::new(TdxVersion::TDX_1_5, device_node) - } - }; - - //build quote generation request header - let mut quote_header = tdx_quote_hdr { - version: 1, - status: 0, - in_len: (mem::size_of_val(&qgs_msg) + 4) as u32, - out_len: 0, - data_len_be_bytes: (1048 as u32).to_be_bytes(), - data: [0; TDX_QUOTE_LEN as usize], - }; - - let qgs_msg_bytes = unsafe { - let ptr = &qgs_msg as *const qgs_msg_get_quote_req as *const u8; - std::slice::from_raw_parts(ptr, mem::size_of::()) - }; - quote_header.data[0..(16 + 8 + TDX_REPORT_LEN) as usize] - .copy_from_slice(&qgs_msg_bytes[0..((16 + 8 + TDX_REPORT_LEN) as usize)]); - - let request = tdx_quote_req { - buf: ptr::addr_of!(quote_header) as u64, - len: TDX_QUOTE_LEN as u64, - }; - - //build the operator code and apply the ioctl command - match tdx_info.tdx_version { - TdxVersion::TDX_1_0 => { - ioctl_read!( - get_quote_1_0_ioctl, - b'T', - TdxOperation::TDX_1_0_GET_QUOTE, - u64 - ); - match unsafe { - get_quote_1_0_ioctl( - tdx_info.device_node.as_raw_fd(), - ptr::addr_of!(request) as *mut u64, - ) - } { - Err(e) => return Err(anyhow!("[get_tdx_quote] Fail to get TDX quote: {:?}", e)), - Ok(_r) => _r, - }; - } - TdxVersion::TDX_1_5 => { - ioctl_read!( - get_quote_1_5_ioctl, - b'T', - TdxOperation::TDX_1_5_GET_QUOTE, - tdx_quote_req - ); - match unsafe { - get_quote_1_5_ioctl( - tdx_info.device_node.as_raw_fd(), - ptr::addr_of!(request) as *mut tdx_quote_req, - ) - } { - Err(e) => return Err(anyhow!("[get_tdx_quote] Fail to get TDX quote: {:?}", e)), - Ok(_r) => _r, - }; - } - }; - - //inspect the response and retrive quote data - let out_len = quote_header.out_len; - let qgs_msg_resp_size = - unsafe { std::mem::transmute::<[u8; 4], u32>(quote_header.data_len_be_bytes) }.to_be(); - - let qgs_msg_resp = unsafe { - let raw_ptr = ptr::addr_of!(quote_header.data) as *mut qgs_msg_get_quote_resp; - raw_ptr.as_mut().unwrap() as &mut qgs_msg_get_quote_resp - }; - - if out_len - qgs_msg_resp_size != 4 { - return Err(anyhow!( - "[get_tdx_quote] Fail to get TDX quote: wrong TDX quote size!" - )); - } - - if qgs_msg_resp.header.major_version != 1 - || qgs_msg_resp.header.minor_version != 0 - || qgs_msg_resp.header.msg_type != 1 - || qgs_msg_resp.header.error_code != 0 - { - return Err(anyhow!( - "[get_tdx_quote] Fail to get TDX quote: QGS response error!" - )); - } - - Ok(qgs_msg_resp.id_quote[0..(qgs_msg_resp.quote_size as usize)].to_vec()) -} - -#[cfg(test)] -mod tdx_attest_tests { - use super::*; - - #[test] - //TDX ENV required: call get_td_report and verify report data embedded in quote - fn get_td_report_verify_report_data() { - let report_data = "XUccU3O9poJXiX53jNGj1w2v4WVAw8TKDyWm8Y0xgJ2khEMyCSCiWfO/sYMEn5xoC8ES2VzXwmKRv9NVu3YnUA=="; - let report = get_td_report(report_data.to_string()).unwrap(); - - let expected_report_data = [ - 93, 71, 28, 83, 115, 189, 166, 130, 87, 137, 126, 119, 140, 209, 163, 215, 13, 175, - 225, 101, 64, 195, 196, 202, 15, 37, 166, 241, 141, 49, 128, 157, 164, 132, 67, 50, 9, - 32, 162, 89, 243, 191, 177, 131, 4, 159, 156, 104, 11, 193, 18, 217, 92, 215, 194, 98, - 145, 191, 211, 85, 187, 118, 39, 80, - ]; - - let mut report_data_in_report: [u8; 64 as usize] = [0; 64 as usize]; - report_data_in_report.copy_from_slice(&report[128..192]); - assert_eq!(report_data_in_report, expected_report_data); - } - - #[test] - //TDX ENV required: call tdx_get_quote and verify report data embedded in quote - fn get_tdx_quote_verify_report_data() { - let report_data = "XUccU3O9poJXiX53jNGj1w2v4WVAw8TKDyWm8Y0xgJ2khEMyCSCiWfO/sYMEn5xoC8ES2VzXwmKRv9NVu3YnUA=="; - let quote = get_tdx_quote(report_data.to_string()).unwrap(); - - let expected_report_data = [ - 93, 71, 28, 83, 115, 189, 166, 130, 87, 137, 126, 119, 140, 209, 163, 215, 13, 175, - 225, 101, 64, 195, 196, 202, 15, 37, 166, 241, 141, 49, 128, 157, 164, 132, 67, 50, 9, - 32, 162, 89, 243, 191, 177, 131, 4, 159, 156, 104, 11, 193, 18, 217, 92, 215, 194, 98, - 145, 191, 211, 85, 187, 118, 39, 80, - ]; - - let mut report_data_in_quote: [u8; 64 as usize] = [0; 64 as usize]; - report_data_in_quote.copy_from_slice("e[568..632]); - assert_eq!(report_data_in_quote, expected_report_data); - } -} diff --git a/service/quote-server/Makefile b/service/quote-server/Makefile deleted file mode 100644 index f597c7d..0000000 --- a/service/quote-server/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2023, Intel Corporation. All rights reserved.
-# SPDX-License-Identifier: Apache-2.0 - -PROJDIR := $(shell readlink -f ..) -TOP_DIR := . -CUR_DIR := $(shell pwd) -PREFIX := -DESTDIR ?= $(PREFIX)/bin - -DEBUG ?= - -TARGET_DIR := target -BIN_NAME := quote_server - -CARGO := /usr/local/cargo/bin/cargo - -ifdef DEBUG - release := - TARGET_DIR := $(TARGET_DIR)/debug -else - release := --release - TARGET_DIR := $(TARGET_DIR)/release -endif - -TARGET := $(TARGET_DIR)/$(BIN_NAME) - -test: - $(CARGO) test - -build: - $(CARGO) build $(release) - -install: - install -D -m0755 $(TARGET) $(DESTDIR) - -uninstall: - rm -f $(DESTDIR)/$(BIN_NAME) - -clean: - $(CARGO) clean \ No newline at end of file diff --git a/service/quote-server/README.md b/service/quote-server/README.md deleted file mode 100644 index 3d80a10..0000000 --- a/service/quote-server/README.md +++ /dev/null @@ -1,109 +0,0 @@ -# Service: CCNP Quote Service - -This service will provide quote generated by underlying TEE platform for remote attestation service to verify the integrity and confidentiality of the trusted computing environment and required software environment. - -## Introduction - -This service provides functionality to fetch quote of underlying TEE platform with nonce as mandatory input and a base64 encoded user data as optional input. The nonce and user data will be digested and added into quote for remote attestation to verify the freshness of the quote and the user specified data. - -The quote server uses Unix domain socket based gRPC to serve the client SDK. And the proto buffer message is as bellow: - -``` -message HealthCheckRequest { - string service = 1; -} - -message HealthCheckResponse { - enum ServingStatus { - UNKNOWN = 0; - SERVING = 1; - NOT_SERVING = 2; - SERVICE_UNKNOWN = 3; - } - ServingStatus status = 1; -} - -service GetQuote { - rpc GetQuote (GetQuoteRequest) returns (GetQuoteResponse); -} - -message GetQuoteRequest { - string user_data = 1; - string nonce = 2; -} - -message GetQuoteResponse { - string quote = 1; - string quote_type = 2; -} - -``` - -## Installation -The quote service can be deployed as either DaemonSet or sidecar according to different user scenarios. - -### Prerequisite -User need to have a kubernetes cluster ready to deploy the services. To simplify the deployment process, we provide Helm as one of the options to deploy the service. Please install Helm by following the [Helm official guide](https://helm.sh/docs/intro/install/). However, user can also use the yaml files located in the manifests folder for deployment. -Also, the ccnp device plugin need to installed before the installation of quote server. Please refer to its [deployment guide](../../device-plugin/ccnp-device-plugin/README.md) for installation. - -### Build docker image -The Dockerfile for the service can be found under `container/ccnp-quote-server` directory. Use the following command to build the image: - -``` -docker build -t ccnp-quote-server: -f container/ccnp-quote-server/Dockerfile . -``` - -> Note: if you are using containerd as the default runtime for kubernetes, don't forget to use the following commands to import the image into containerd first: -``` -docker save -o ccnp-quote-server.tar ccnp-quote-server: -ctr -n=k8s.io image import ccnp-quote-server.tar -``` - -### Deploy as DaemonSet in Kubernetes -1. deploy using helm chart -``` -cd deployment/ -# edit the value file for quote-server helm chart and run: -helm install charts/quote-server --generate-name -``` - -2. deploy using manifests yaml file - -please check file `deployment/manifests/quote-server-deployment.yaml` to confirm the container image to use and run: -``` -kubectl apply -f deployment/manifests/quote-server-deployment.yaml -``` - -## Testing -You can play with service on host by following the steps below: - -1. Start the quote service - -Tips: please make sure `/run/ccnp/uds` directory exists with other user can write to it: -``` -root@tdx-guest:~# ls -l /run/ccnp/ -total 0 -drwxr-xrwx 2 root root 60 Sep 1 05:05 uds -``` - -And then build and run the quote server with binary: -``` -cd service/quote-server -make build -./target/release/quote_server -``` -2. Play with the service -Use the `grpcurl` as the tool to play with the service. Please follow the [official documentation](https://github.com/fullstorydev/grpcurl) to install grpcurl - -Get quote from the TDX platform: -``` -grpcurl -authority "dummy" -d '{"user_data": "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4", "nonce":"IXUKoBO1UM3c1wopN4sY"}' -plaintext -unix /run/ccnp/uds/quote-server.sock quoteserver.GetQuote.GetQuote -``` - -and the output should be as bellow: -``` -{ - "quote": "\"BAACAIEAAAAAAAAAk5pyM/ecTKmUCg2zlX8GB6P8pz1eLkNLuYzlFq7gmQ4AAAAABAAGAAAAAAAAAAAAAAAAAEj6aZSdsIAC7oQlKEf1cpiLHW5WjsE1P2TLbA/ZBTdfaa2VnA6vd0escKOSeJMCoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAADnAgYAAAAAAKSgAzRsWhmm/SUEcehyvQcdjJLXQxq9pGNBeAihc4OqDUKYeBS8kvX1nGBEtnf1FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO8sw2a5sIgf6+MgszlJcgpq4sP0tqpfKTspZny2PWPOYiJbt1aPe1rpeqDtoa+NreW8yD5Jj8ypKTGA+WfwPH77+negDf9ZWNeonsxRtNtsLoUabMeutZ+xSCbs5gUWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAO+/PqJMpmXxEfoJELnxuPmAbw69VjN9ZQQqe3NjVd72ql13C43JW093ytpa7ipkSR7msIelxHz9nmDTkSucmGPMEAAA0doq0wnfzK1RM8LVMVECwOpiI5ePJkQ7KClggtiBrCrBhE6p3ECY4SUVhWET733tRdTwhkH3JNCkvTIRGeXE3SY1oRIxb7dVmrMVrWdmmfldJoB8RvpN7HOs/g788NOgFoemd5F95mGdNVJ3v0ppPvgJQ5ryby6SOYHAsL25dbkGAEYQAAAGBhMVA/8ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAAAOcAAAAAAAAAOWseNYAkJ5SHxHr5xWG93BUlhjmq0t2vdgCQ70Y/C4QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANyeKnxvlI8XR040p/xD7QMPfBVj8bq932NAyC4OVKjFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOYzIRlhSwSQeVYIlVCCAgcDb+K5pY0hOxqAEm1vN5p/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXrF4+4CGy/IYdLV5k30DF9yMXwa6zYhBz8QproGhnTZPTIEXSIJLkzgEx9OaFrepQWCu+wbggzJVLqv9hg6a5IAAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHwUAXg4AAC0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlFOERDQ0JKYWdBd0lCQWdJVWR2clZDNnpJTFRvbGI0ZEt5RGhsbFlaUEc1RXdDZ1lJS29aSXpqMEVBd0l3CmNERWlNQ0FHQTFVRUF3d1pTVzUwWld3Z1UwZFlJRkJEU3lCUWJHRjBabTl5YlNCRFFURWFNQmdHQTFVRUNnd1IKU1c1MFpXd2dRMjl5Y0c5eVlYUnBiMjR4RkRBU0JnTlZCQWNNQzFOaGJuUmhJRU5zWVhKaE1Rc3dDUVlEVlFRSQpEQUpEUVRFTE1Ba0dBMVVFQmhNQ1ZWTXdIaGNOTWpNd05URTJNRGd5TXpJd1doY05NekF3TlRFMk1EZ3lNekl3CldqQndNU0l3SUFZRFZRUUREQmxKYm5SbGJDQlRSMWdnVUVOTElFTmxjblJwWm1sallYUmxNUm93R0FZRFZRUUsKREJGSmJuUmxiQ0JEYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRnVkR0VnUTJ4aGNtRXhDekFKQmdOVgpCQWdNQWtOQk1Rc3dDUVlEVlFRR0V3SlZVekJaTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEEwSUFCUHZQClNtKzJtU1R2TzE0RkhpOXd3K05qYUhzazhyVHFQQ0xEMDZ3MmtJVE9yb0RYSmN5NDBMbHRZemFBZ3JXR2FsWFoKTy9GY3cxc0padDZZdFNRVHlyU2pnZ01NTUlJRENEQWZCZ05WSFNNRUdEQVdnQlNWYjEzTnZSdmg2VUJKeWRUMApNODRCVnd2ZVZEQnJCZ05WSFI4RVpEQmlNR0NnWHFCY2hscG9kSFJ3Y3pvdkwyRndhUzUwY25WemRHVmtjMlZ5CmRtbGpaWE11YVc1MFpXd3VZMjl0TDNObmVDOWpaWEowYVdacFkyRjBhVzl1TDNZMEwzQmphMk55YkQ5allUMXcKYkdGMFptOXliU1psYm1OdlpHbHVaejFrWlhJd0hRWURWUjBPQkJZRUZEUGs4eit4L0JtVkw5UDVJTkRaNlhlUwpTOHR4TUE0R0ExVWREd0VCL3dRRUF3SUd3REFNQmdOVkhSTUJBZjhFQWpBQU1JSUNPUVlKS29aSWh2aE5BUTBCCkJJSUNLakNDQWlZd0hnWUtLb1pJaHZoTkFRMEJBUVFRUGYyUXdCNHRTYzhyRmxvZGJJQzlCVENDQVdNR0NpcUcKU0liNFRRRU5BUUl3Z2dGVE1CQUdDeXFHU0liNFRRRU5BUUlCQWdFRk1CQUdDeXFHU0liNFRRRU5BUUlDQWdFRgpNQkFHQ3lxR1NJYjRUUUVOQVFJREFnRUNNQkFHQ3lxR1NJYjRUUUVOQVFJRUFnRUNNQkFHQ3lxR1NJYjRUUUVOCkFRSUZBZ0VETUJBR0N5cUdTSWI0VFFFTkFRSUdBZ0VCTUJBR0N5cUdTSWI0VFFFTkFRSUhBZ0VBTUJBR0N5cUcKU0liNFRRRU5BUUlJQWdFRE1CQUdDeXFHU0liNFRRRU5BUUlKQWdFQU1CQUdDeXFHU0liNFRRRU5BUUlLQWdFQQpNQkFHQ3lxR1NJYjRUUUVOQVFJTEFnRUFNQkFHQ3lxR1NJYjRUUUVOQVFJTUFnRUFNQkFHQ3lxR1NJYjRUUUVOCkFRSU5BZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSU9BZ0VBTUJBR0N5cUdTSWI0VFFFTkFRSVBBZ0VBTUJBR0N5cUcKU0liNFRRRU5BUUlRQWdFQU1CQUdDeXFHU0liNFRRRU5BUUlSQWdFTE1COEdDeXFHU0liNFRRRU5BUUlTQkJBRgpCUUlDQXdFQUF3QUFBQUFBQUFBQU1CQUdDaXFHU0liNFRRRU5BUU1FQWdBQU1CUUdDaXFHU0liNFRRRU5BUVFFCkJnQ0Fid1VBQURBUEJnb3Foa2lHK0UwQkRRRUZDZ0VCTUI0R0NpcUdTSWI0VFFFTkFRWUVFQUxFbzJLdDd4d3QKNmhQZGdZekRNMFl3UkFZS0tvWklodmhOQVEwQkJ6QTJNQkFHQ3lxR1NJYjRUUUVOQVFjQkFRSC9NQkFHQ3lxRwpTSWI0VFFFTkFRY0NBUUVBTUJBR0N5cUdTSWI0VFFFTkFRY0RBUUgvTUFvR0NDcUdTTTQ5QkFNQ0EwZ0FNRVVDCklBTURNUDNSaUJOYVpuM2NLUjducFVxNDFkTm1HNzIzZlFYcWlJVTU0U09KQWlFQSsrZW9Ta1ZOa2NnbERLZncKaDNDbGx6UzNway9hSGhYNjZDUjc1TllJanpnPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCi0tLS0tQkVHSU4gQ0VSVElGSUNBVEUtLS0tLQpNSUlDbGpDQ0FqMmdBd0lCQWdJVkFKVnZYYzI5RytIcFFFbkoxUFF6emdGWEM5NVVNQW9HQ0NxR1NNNDlCQU1DCk1HZ3hHakFZQmdOVkJBTU1FVWx1ZEdWc0lGTkhXQ0JTYjI5MElFTkJNUm93R0FZRFZRUUtEQkZKYm5SbGJDQkQKYjNKd2IzSmhkR2x2YmpFVU1CSUdBMVVFQnd3TFUyRnVkR0VnUTJ4aGNtRXhDekFKQmdOVkJBZ01Ba05CTVFzdwpDUVlEVlFRR0V3SlZVekFlRncweE9EQTFNakV4TURVd01UQmFGdzB6TXpBMU1qRXhNRFV3TVRCYU1IQXhJakFnCkJnTlZCQU1NR1VsdWRHVnNJRk5IV0NCUVEwc2dVR3hoZEdadmNtMGdRMEV4R2pBWUJnTlZCQW9NRVVsdWRHVnMKSUVOdmNuQnZjbUYwYVc5dU1SUXdFZ1lEVlFRSERBdFRZVzUwWVNCRGJHRnlZVEVMTUFrR0ExVUVDQXdDUTBFeApDekFKQmdOVkJBWVRBbFZUTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFTlNCLzd0MjFsWFNPCjJDdXpweHc3NGVKQjcyRXlER2dXNXJYQ3R4MnRWVExxNmhLazZ6K1VpUlpDbnFSN3BzT3ZncUZlU3hsbVRsSmwKZVRtaTJXWXozcU9CdXpDQnVEQWZCZ05WSFNNRUdEQVdnQlFpWlF6V1dwMDBpZk9EdEpWU3YxQWJPU2NHckRCUwpCZ05WSFI4RVN6QkpNRWVnUmFCRGhrRm9kSFJ3Y3pvdkwyTmxjblJwWm1sallYUmxjeTUwY25WemRHVmtjMlZ5CmRtbGpaWE11YVc1MFpXd3VZMjl0TDBsdWRHVnNVMGRZVW05dmRFTkJMbVJsY2pBZEJnTlZIUTRFRmdRVWxXOWQKemIwYjRlbEFTY25VOURQT0FWY0wzbFF3RGdZRFZSMFBBUUgvQkFRREFnRUdNQklHQTFVZEV3RUIvd1FJTUFZQgpBZjhDQVFBd0NnWUlLb1pJemowRUF3SURSd0F3UkFJZ1hzVmtpMHcraTZWWUdXM1VGLzIydWFYZTBZSkRqMVVlCm5BK1RqRDFhaTVjQ0lDWWIxU0FtRDV4a2ZUVnB2bzRVb3lpU1l4ckRXTG1VUjRDSTlOS3lmUE4rCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUNqekNDQWpTZ0F3SUJBZ0lVSW1VTTFscWROSW56ZzdTVlVyOVFHemtuQnF3d0NnWUlLb1pJemowRUF3SXcKYURFYU1CZ0dBMVVFQXd3UlNXNTBaV3dnVTBkWUlGSnZiM1FnUTBFeEdqQVlCZ05WQkFvTUVVbHVkR1ZzSUVOdgpjbkJ2Y21GMGFXOXVNUlF3RWdZRFZRUUhEQXRUWVc1MFlTQkRiR0Z5WVRFTE1Ba0dBMVVFQ0F3Q1EwRXhDekFKCkJnTlZCQVlUQWxWVE1CNFhEVEU0TURVeU1URXdORFV4TUZvWERUUTVNVEl6TVRJek5UazFPVm93YURFYU1CZ0cKQTFVRUF3d1JTVzUwWld3Z1UwZFlJRkp2YjNRZ1EwRXhHakFZQmdOVkJBb01FVWx1ZEdWc0lFTnZjbkJ2Y21GMAphVzl1TVJRd0VnWURWUVFIREF0VFlXNTBZU0JEYkdGeVlURUxNQWtHQTFVRUNBd0NRMEV4Q3pBSkJnTlZCQVlUCkFsVlRNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVDNm5Fd01ESVlaT2ovaVBXc0N6YUVLaTcKMU9pT1NMUkZoV0dqYm5CVkpmVm5rWTR1M0lqa0RZWUwwTXhPNG1xc3lZamxCYWxUVll4RlAyc0pCSzV6bEtPQgp1ekNCdURBZkJnTlZIU01FR0RBV2dCUWlaUXpXV3AwMGlmT0R0SlZTdjFBYk9TY0dyREJTQmdOVkhSOEVTekJKCk1FZWdSYUJEaGtGb2RIUndjem92TDJObGNuUnBabWxqWVhSbGN5NTBjblZ6ZEdWa2MyVnlkbWxqWlhNdWFXNTAKWld3dVkyOXRMMGx1ZEdWc1UwZFlVbTl2ZEVOQkxtUmxjakFkQmdOVkhRNEVGZ1FVSW1VTTFscWROSW56ZzdTVgpVcjlRR3prbkJxd3dEZ1lEVlIwUEFRSC9CQVFEQWdFR01CSUdBMVVkRXdFQi93UUlNQVlCQWY4Q0FRRXdDZ1lJCktvWkl6ajBFQXdJRFNRQXdSZ0loQU9XLzVRa1IrUzlDaVNEY05vb3dMdVBSTHNXR2YvWWk3R1NYOTRCZ3dUd2cKQWlFQTRKMGxySG9NcytYbzVvL3NYNk85UVd4SFJBdlpVR09kUlE3Y3ZxUlhhcUk9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KAA==\"", - "quoteType": "TDX" -} -``` diff --git a/service/quote-server/api/quote-server.proto b/service/quote-server/api/quote-server.proto deleted file mode 100644 index 4178e80..0000000 --- a/service/quote-server/api/quote-server.proto +++ /dev/null @@ -1,30 +0,0 @@ -syntax = "proto3"; -package quoteserver; - -message HealthCheckRequest { - string service = 1; -} - -message HealthCheckResponse { - enum ServingStatus { - UNKNOWN = 0; - SERVING = 1; - NOT_SERVING = 2; - SERVICE_UNKNOWN = 3; - } - ServingStatus status = 1; -} - -service GetQuote { - rpc GetQuote (GetQuoteRequest) returns (GetQuoteResponse); -} - -message GetQuoteRequest { - string user_data = 1; - string nonce = 2; -} - -message GetQuoteResponse { - string quote = 1; - string quote_type = 2; -} diff --git a/service/quote-server/deny.toml b/service/quote-server/deny.toml deleted file mode 100644 index 6e656f7..0000000 --- a/service/quote-server/deny.toml +++ /dev/null @@ -1,35 +0,0 @@ -[advisories] -vulnerability = "deny" -unmaintained = "warn" -yanked = "warn" -notice = "warn" - -[licenses] -unlicensed = "warn" -allow = [ - "MIT", - "Apache-2.0", - "ISC", - "BSD-3-Clause", - "Unicode-DFS-2016", -] - -copyleft = "warn" -allow-osi-fsf-free = "neither" -default = "deny" -confidence-threshold = 0.8 - -[[licenses.clarify]] -name = "ring" -expression = "MIT AND ISC AND OpenSSL" -license-files = [ - { path = "LICENSE", hash = 0xbd0eed23 } -] - -[bans] -multiple-versions = "warn" -wildcards = "allow" - -[sources] -unknown-registry = "warn" -unknown-git = "warn" \ No newline at end of file diff --git a/service/quote-server/src/quote_server.rs b/service/quote-server/src/quote_server.rs deleted file mode 100644 index aa0a7c9..0000000 --- a/service/quote-server/src/quote_server.rs +++ /dev/null @@ -1,308 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 -*/ - -use clap::Parser; -use quote_server::get_quote_server::{GetQuote, GetQuoteServer}; -use quote_server::{GetQuoteRequest, GetQuoteResponse}; -use tokio::net::UnixListener; -use tokio_stream::wrappers::UnixListenerStream; -use tonic::{transport::Server, Request, Response, Status}; - -pub mod tee; -use tee::*; - -pub mod quote_server { - tonic::include_proto!("quoteserver"); - - pub(crate) const FILE_DESCRIPTOR_SET: &[u8] = - tonic::include_file_descriptor_set!("quote_server_descriptor"); -} - -pub struct CCNPGetQuote { - local_tee: tee::TeeType, -} - -impl CCNPGetQuote { - fn new(_local_tee: TeeType) -> Self { - CCNPGetQuote { - local_tee: _local_tee, - } - } -} - -#[tonic::async_trait] -impl GetQuote for CCNPGetQuote { - async fn get_quote( - &self, - request: Request, - ) -> Result, Status> { - let msg; - let req = request.into_inner(); - - println!( - "Got a request with: user_data = {:?}, nonce = {:?}", - req.user_data, req.nonce - ); - let result = get_quote(self.local_tee.clone(), req.user_data, req.nonce); - match result { - Ok(q) => { - msg = Response::new(quote_server::GetQuoteResponse { - quote: q, - quote_type: format!("{:?}", self.local_tee).to_string(), - }) - } - Err(e) => return Err(Status::internal(e.to_string())), - } - Ok(msg) - } -} - -#[derive(Parser)] -struct Cli { - port: String, -} - -#[tokio::main] -async fn main() -> Result<(), Box> { - let path = "/run/ccnp/uds/quote-server.sock"; - let _ = std::fs::remove_file(path); - let uds = match UnixListener::bind(path) { - Ok(r) => r, - Err(e) => panic!("[quote-server]: bind UDS socket error: {:?}", e), - }; - let uds_stream = UnixListenerStream::new(uds); - - let getquote = CCNPGetQuote::new({ - match tee::get_tee_type() { - tee::TeeType::PLAIN => panic!("[quote-server]: Not found any TEE device!"), - t => t, - } - }); - - let (mut health_reporter, health_service) = tonic_health::server::health_reporter(); - health_reporter - .set_serving::>() - .await; - - let reflection_service = tonic_reflection::server::Builder::configure() - .register_encoded_file_descriptor_set(quote_server::FILE_DESCRIPTOR_SET) - .build() - .unwrap(); - - println!( - "Starting quote server in {} enviroment...", - format!("{:?}", tee::get_tee_type()).to_string() - ); - - Server::builder() - .add_service(reflection_service) - .add_service(health_service) - .add_service(GetQuoteServer::new(getquote)) - .serve_with_incoming(uds_stream) - .await?; - Ok(()) -} - -#[cfg(test)] -mod quote_server_tests { - use super::*; - use crate::quote_server::get_quote_client::GetQuoteClient; - use serial_test::serial; - use tokio::net::UnixStream; - use tonic::transport::{Endpoint, Uri}; - use tower::service_fn; - - async fn creat_server() { - let path = "/tmp/quote-server.sock"; - let _ = std::fs::remove_file(path); - let uds = match UnixListener::bind(path) { - Ok(r) => r, - Err(e) => panic!("[quote-server]: bind UDS socket error: {:?}", e), - }; - let uds_stream = UnixListenerStream::new(uds); - - let getquote = CCNPGetQuote::new({ - match tee::get_tee_type() { - tee::TeeType::PLAIN => panic!("[quote-server]: Not found any TEE device!"), - t => t, - } - }); - - tokio::spawn(async { - Server::builder() - .add_service(GetQuoteServer::new(getquote)) - .serve_with_incoming(uds_stream) - .await - .unwrap(); - }); - } - - #[tokio::test] - #[serial] - //test start server and send request - async fn request_to_server_normal() { - creat_server().await; - - let channel = Endpoint::try_from("http://[::]:40081") - .unwrap() - .connect_with_connector(service_fn(|_: Uri| { - let path = "/tmp/quote-server.sock"; - UnixStream::connect(path) - })) - .await - .unwrap(); - - let mut client = GetQuoteClient::new(channel); - - let request = tonic::Request::new(GetQuoteRequest { - user_data: base64::encode("123456781234567812345678123456781234567812345678"), - nonce: "12345678".to_string(), - }); - - let response = client.get_quote(request).await.unwrap().into_inner(); - assert_eq!(response.quote_type, "TDX"); - } - - #[tokio::test] - #[serial] - async fn request_to_server_empty_user_data() { - creat_server().await; - - let channel = Endpoint::try_from("http://[::]:40081") - .unwrap() - .connect_with_connector(service_fn(|_: Uri| { - let path = "/tmp/quote-server.sock"; - UnixStream::connect(path) - })) - .await - .unwrap(); - - let mut client = GetQuoteClient::new(channel); - - let request = tonic::Request::new(GetQuoteRequest { - user_data: "".to_string(), - nonce: "12345678".to_string(), - }); - - let response = client.get_quote(request).await.unwrap().into_inner(); - assert_eq!(response.quote_type, "TDX"); - assert_ne!(response.quote.len(), 0); - } - - #[tokio::test] - #[serial] - async fn request_to_server_long_user_data() { - creat_server().await; - - let channel = Endpoint::try_from("http://[::]:40081") - .unwrap() - .connect_with_connector(service_fn(|_: Uri| { - let path = "/tmp/quote-server.sock"; - UnixStream::connect(path) - })) - .await - .unwrap(); - - let mut client = GetQuoteClient::new(channel); - - let request = tonic::Request::new(GetQuoteRequest { - user_data: "123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678".to_string(), - nonce: "12345678".to_string(), - }); - - let response = client.get_quote(request).await.unwrap().into_inner(); - assert_eq!(response.quote_type, "TDX"); - assert_ne!(response.quote.len(), 0); - } - - #[tokio::test] - #[serial] - async fn request_to_server_empty_nonce() { - creat_server().await; - - let channel = Endpoint::try_from("http://[::]:40081") - .unwrap() - .connect_with_connector(service_fn(|_: Uri| { - let path = "/tmp/quote-server.sock"; - UnixStream::connect(path) - })) - .await - .unwrap(); - - let mut client = GetQuoteClient::new(channel); - - let request = tonic::Request::new(GetQuoteRequest { - user_data: "123456781234567812345678123456781234567812345678".to_string(), - nonce: "".to_string(), - }); - - let response = client.get_quote(request).await.unwrap().into_inner(); - assert_eq!(response.quote_type, "TDX"); - assert_ne!(response.quote.len(), 0); - } - - #[tokio::test] - #[serial] - async fn request_to_server_log_nonce() { - creat_server().await; - - let channel = Endpoint::try_from("http://[::]:40081") - .unwrap() - .connect_with_connector(service_fn(|_: Uri| { - let path = "/tmp/quote-server.sock"; - UnixStream::connect(path) - })) - .await - .unwrap(); - - let mut client = GetQuoteClient::new(channel); - - let request = tonic::Request::new(GetQuoteRequest { - user_data: "123456781234567812345678123456781234567812345678".to_string(), - nonce: "123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678123456781234567812345678".to_string(), - }); - - let response = client.get_quote(request).await.unwrap().into_inner(); - assert_eq!(response.quote_type, "TDX"); - assert_ne!(response.quote.len(), 0); - } - - #[tokio::test] - #[serial] - async fn request_to_server_verify_report_data() { - creat_server().await; - - let channel = Endpoint::try_from("http://[::]:40081") - .unwrap() - .connect_with_connector(service_fn(|_: Uri| { - let path = "/tmp/quote-server.sock"; - UnixStream::connect(path) - })) - .await - .unwrap(); - - let mut client = GetQuoteClient::new(channel); - - let request = tonic::Request::new(GetQuoteRequest { - user_data: "YWJjZGVmZw==".to_string(), - nonce: "MTIzNDU2Nzg=".to_string(), - }); - - let response = client.get_quote(request).await.unwrap().into_inner(); - - let expected_report_data = [ - 93, 71, 28, 83, 115, 189, 166, 130, 87, 137, 126, 119, 140, 209, 163, 215, 13, 175, - 225, 101, 64, 195, 196, 202, 15, 37, 166, 241, 141, 49, 128, 157, 164, 132, 67, 50, 9, - 32, 162, 89, 243, 191, 177, 131, 4, 159, 156, 104, 11, 193, 18, 217, 92, 215, 194, 98, - 145, 191, 211, 85, 187, 118, 39, 80, - ]; - - assert_eq!(response.quote_type, "TDX"); - let quote = base64::decode(response.quote.replace("\"", "")).unwrap(); - let mut report_data_in_quote: [u8; 64 as usize] = [0; 64 as usize]; - report_data_in_quote.copy_from_slice("e[568..632]); - assert_eq!(report_data_in_quote, expected_report_data); - } -} diff --git a/service/quote-server/src/tee.rs b/service/quote-server/src/tee.rs deleted file mode 100644 index 5ba9915..0000000 --- a/service/quote-server/src/tee.rs +++ /dev/null @@ -1,425 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 -*/ - -use anyhow::*; -use sha2::{Digest, Sha512}; -use std::path::Path; -use std::result::Result::Ok; - -#[derive(Debug, Clone)] -pub enum TeeType { - TDX, - SEV, - TPM, - PLAIN, -} - -pub fn get_tee_type() -> TeeType { - if Path::new("/dev/tpm0").exists() { - TeeType::TPM - } else if Path::new("/dev/tdx-guest").exists() - || Path::new("/dev/tdx-attest").exists() - || Path::new("/dev/tdx_guest").exists() - { - if Path::new("/dev/tdx-attest").exists() { - panic!("[get_tee_type]: Deprecated device node /dev/tdx-attest, please upgrade to use /dev/tdx-guest or /dev/tdx_guest"); - } - TeeType::TDX - } else if Path::new("/dev/sev-guest").exists() || Path::new("/dev/sev").exists() { - TeeType::SEV - } else { - TeeType::PLAIN - } -} - -fn generate_tdx_report_data( - report_data: Option, - nonce: String, -) -> Result { - let nonce_decoded = match base64::decode(nonce) { - Ok(v) => v, - Err(e) => { - return Err(anyhow!( - "[generate_tdx_report_data] nonce is not base64 encoded: {:?}", - e - )) - } - }; - let mut hasher = Sha512::new(); - hasher.update(nonce_decoded); - let _ret = match report_data { - Some(_encoded_report_data) => { - if _encoded_report_data.is_empty() { - hasher.update("") - } else { - let decoded_report_data = match base64::decode(_encoded_report_data) { - Ok(v) => v, - Err(e) => { - return Err(anyhow!( - "[generate_tdx_report_data] user data is not base64 encoded: {:?}", - e - )) - } - }; - hasher.update(decoded_report_data) - } - } - None => hasher.update(""), - }; - let hash_array: [u8; 64] = hasher - .finalize() - .as_slice() - .try_into() - .expect("[generate_tdx_report_data] Wrong length of report data"); - Ok(base64::encode(hash_array)) -} - -fn get_tdx_quote(report_data: Option, nonce: String) -> Result { - let tdx_report_data = match generate_tdx_report_data(report_data, nonce) { - Ok(v) => v, - Err(e) => { - return Err(anyhow!("[get_tdx_quote]: {:?}", e)); - } - }; - - let quote = match tdx_attest::get_tdx_quote(tdx_report_data) { - Err(e) => panic!("[get_tdx_quote] Fail to get TDX quote: {:?}", e), - Ok(q) => base64::encode(q), - }; - - serde_json::to_string("e).map_err(|e| anyhow!("[get_tdx_quote]: {:?}", e)) -} - -fn get_tpm_quote() -> Result { - Err(anyhow!("TPM to be supported!")) -} - -fn get_sev_quote() -> Result { - Err(anyhow!("SEV to be supported!")) -} - -pub fn get_quote(local_tee: TeeType, user_data: String, nonce: String) -> Result { - match local_tee { - TeeType::TDX => get_tdx_quote(Some(user_data), nonce), - TeeType::TPM => get_tpm_quote(), - TeeType::SEV => get_sev_quote(), - _ => Err(anyhow!("Unexpected case!")), - } -} - -#[cfg(test)] -mod tests { - - use super::*; - - #[test] - //generate_tdx_report allow empty nonce - fn generate_tdx_report_data_empty_nonce() { - let result = generate_tdx_report_data(Some("YWJjZGVmZw==".to_string()), "".to_string()); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow optional report data - fn tdx_get_quote_report_data_no_report_data() { - let result = generate_tdx_report_data(None, "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow empty report data string - fn generate_tdx_report_data_report_data_size_0() { - let result = - generate_tdx_report_data(Some("".to_string()), "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow 8 bytes report data string - fn generate_tdx_report_data_report_data_size_8() { - let result = generate_tdx_report_data( - Some("YWJjZGVmZw==".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow 48 bytes report data string - fn generate_tdx_report_data_size_report_data_size_48() { - // this one should be standard 48 bytes base64 encoded report data - // "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4" is base64 of "123456781234567812345678123456781234567812345678", 48 bytes - let result = generate_tdx_report_data( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report require report data string is base64 encoded - fn generate_tdx_report_data_report_data_not_base64_encoded() { - //coming in report data should always be base64 encoded - let result = generate_tdx_report_data( - Some("XD^%*!x".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //generate_tdx_report require nonce string is base64 encoded - fn generate_tdx_report_data_nonce_not_base64_encoded() { - //coming in nonce should always be base64 encoded - let result = generate_tdx_report_data( - Some("IXUKoBO1XEFBPwopN4sY".to_string()), - "XD^%*!x".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //generate_tdx_report require nonce string is base64 encoded - fn generate_tdx_report_data_nonce_short_not_base64_encoded() { - //coming in nonce should always be base64 encoded - let result = - generate_tdx_report_data(Some("IXUKoBO1XEFBPwopN4sY".to_string()), "123".to_string()); - assert!(result.is_err()); - } - - #[test] - //generate_tdx_report require report data string is base64 encoded - fn generate_tdx_report_data_report_data_short_not_base64_encoded() { - //coming in report data should always be base64 encoded - let result = - generate_tdx_report_data(Some("123".to_string()), "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_err()); - } - - #[test] - //generate_tdx_report check result as expected - //original report_data = "abcdefgh", orginal nonce = "12345678" - fn generate_tdx_report_data_report_data_nonce_base64_encoded_as_expected() { - let result = - generate_tdx_report_data(Some("YWJjZGVmZw==".to_string()), "MTIzNDU2Nzg=".to_string()) - .unwrap(); - let expected_hash = [ - 93, 71, 28, 83, 115, 189, 166, 130, 87, 137, 126, 119, 140, 209, 163, 215, 13, 175, - 225, 101, 64, 195, 196, 202, 15, 37, 166, 241, 141, 49, 128, 157, 164, 132, 67, 50, 9, - 32, 162, 89, 243, 191, 177, 131, 4, 159, 156, 104, 11, 193, 18, 217, 92, 215, 194, 98, - 145, 191, 211, 85, 187, 118, 39, 80, - ]; - let generated_hash = base64::decode(result).unwrap(); - assert_eq!(generated_hash, expected_hash); - } - - #[test] - //generate_tdx_report allow long report data string - fn generate_tdx_report_data_long_tdx_report_data() { - let result = generate_tdx_report_data( - Some( - "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzgx\ - MjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEy\ - MzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIz\ - NDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0\ - NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1\ - Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2\ - NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4Cg==" - .to_string(), - ), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report allow long nonce string - fn generate_tdx_report_data_long_nonce() { - let result = generate_tdx_report_data( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzgx\ - MjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEy\ - MzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIz\ - NDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0\ - NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1\ - Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2\ - NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4Cg==" - .to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //generate_tdx_report_data generated report data is 64 bytes - fn generate_tdx_report_data_report_data_is_64_bytes() { - let report_data_hashed = match generate_tdx_report_data( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ) { - Ok(r) => r, - Err(_) => todo!(), - }; - let generated_hash_len = base64::decode(report_data_hashed).unwrap().len(); - assert_eq!(generated_hash_len, 64); - } - - #[test] - //TDX ENV required: tdx_get_quote allow empty nonce - fn tdx_get_quote_empty_nonce() { - let result = get_tdx_quote(Some("YWJjZGVmZw==".to_string()), "".to_string()); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow 0 bytes report data string - fn tdx_get_quote_report_data_size_0() { - let result = get_tdx_quote(Some("".to_string()), "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow 8 bytes report data string - fn tdx_get_quote_report_data_size_8() { - // "YWJjZGVmZw==" is base64 of "abcdefg", 8 bytes - let result = get_tdx_quote( - Some("YWJjZGVmZw==".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow 48 bytes report data string - fn tdx_get_quote_report_data_size_48() { - let result = get_tdx_quote( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow optional report data - fn tdx_get_quote_report_data_null() { - let result = get_tdx_quote(None, "IXUKoBO1XEFBPwopN4sY".to_string()); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote require report data string is base64 encoded - fn tdx_get_quote_report_data_not_base64_encoded() { - let result = get_tdx_quote( - Some("XD^%*!x".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //TDX ENV required: tdx_get_quote require nonce string is base64 encoded - fn tdx_get_quote_nonce_not_base64_encoded() { - let result = get_tdx_quote( - Some("IXUKoBO1XEFBPwopN4sY".to_string()), - "XD^%*!x".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow long report data string - fn tdx_get_quote_long_tdx_report_data() { - let result = get_tdx_quote( - Some( - "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzgx\ - MjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEy\ - MzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIz\ - NDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0\ - NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1\ - Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2\ - NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4Cg==" - .to_string(), - ), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: tdx_get_quote allow long nonce string - fn tdx_get_quote_long_nonce() { - let result = get_tdx_quote( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2Nzgx\ - MjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEy\ - MzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIz\ - NDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0\ - NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1\ - Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2\ - NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4Cg==" - .to_string(), - ); - assert!(result.is_ok()); - } - - #[test] - //TDX ENV required: get_tdx_quote return non-empty encoded quote string - fn tdx_get_quote_report_data_encoded_quote_is_not_0_bytes() { - let quote = match get_tdx_quote( - Some("MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4MTIzNDU2NzgxMjM0NTY3ODEyMzQ1Njc4".to_string()), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ) { - Ok(r) => r, - Err(_) => todo!(), - }; - assert_ne!(quote.len(), 0); - } - - #[test] - //get_quote does not allow tee type beyond TDX/SEV/TPM - fn get_quote_wrong_tee_type() { - let result = get_quote( - TeeType::PLAIN, - "".to_string(), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //get_quote does not support SEV for now - fn get_quote_sev_tee_type() { - //does not allow tee type beyond TDX/SEV/TPM - let result = get_quote( - TeeType::SEV, - "".to_string(), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //get_quote does not support TPM for now - fn get_quote_tpm_tee_type() { - //does not allow tee type beyond TDX/SEV/TPM - let result = get_quote( - TeeType::TPM, - "".to_string(), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_err()); - } - - #[test] - //get_quote support TDX now - fn get_quote_tdx_tee_type() { - //does not allow tee type beyond TDX/SEV/TPM - let result = get_quote( - TeeType::TDX, - "".to_string(), - "IXUKoBO1XEFBPwopN4sY".to_string(), - ); - assert!(result.is_ok()); - } -} diff --git a/service/quote-server/tdx_attest/Cargo.toml b/service/quote-server/tdx_attest/Cargo.toml deleted file mode 100644 index d543db9..0000000 --- a/service/quote-server/tdx_attest/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "tdx_attest" -version = "0.1.1" -edition = "2021" -authors = ["Hairong Chen "] -description = "A rust crate to retrieve TD Report and TDX quote via ioctl" -readme = "README.md" -license = "Apache-2.0" -repository = "https://github.com/confidential-cloud-native-primitives" - -[lib] -name = "tdx_attest" -path = "src/tdx_attest.rs" - -[dependencies] -nix = "0.26.2" -base64 = "0.13.0" -anyhow = "1.0" \ No newline at end of file diff --git a/service/quote-server/tdx_attest/README.md b/service/quote-server/tdx_attest/README.md deleted file mode 100644 index 26aba20..0000000 --- a/service/quote-server/tdx_attest/README.md +++ /dev/null @@ -1 +0,0 @@ -A rust crate to retrieve TD Report and TDX quote via ioctl \ No newline at end of file diff --git a/service/quote-server/tdx_attest/src/tdx_attest.rs b/service/quote-server/tdx_attest/src/tdx_attest.rs deleted file mode 100644 index 3420c71..0000000 --- a/service/quote-server/tdx_attest/src/tdx_attest.rs +++ /dev/null @@ -1,453 +0,0 @@ -/* -* Copyright (c) 2023, Intel Corporation. All rights reserved.
-* SPDX-License-Identifier: Apache-2.0 -*/ - -#![allow(non_camel_case_types)] - -use anyhow::*; -use nix::*; -use std::convert::TryInto; -use std::fs::File; -use std::mem; -use std::os::unix::io::AsRawFd; -use std::path::Path; -use std::ptr; -use std::result::Result; -use std::result::Result::Ok; - -#[repr(C)] -pub struct tdx_1_0_report_req { - subtype: u8, // Subtype of TDREPORT: fixed as 0 by TDX Module specification - reportdata: u64, // User-defined REPORTDATA to be included into TDREPORT - rpd_len: u32, // Length of the REPORTDATA: fixed as 64 bytes by the TDX Module specification - tdreport: u64, // TDREPORT output from TDCALL[TDG.MR.REPORT] - tdr_len: u32, // Length of the TDREPORT: fixed as 1024 bytes by the TDX Module specification -} - -#[repr(C)] -pub struct tdx_1_5_report_req { - reportdata: [u8; REPORT_DATA_LEN as usize], // User buffer with REPORTDATA to be included into TDREPORT - tdreport: [u8; TDX_REPORT_LEN as usize], // User buffer to store TDREPORT output from TDCALL[TDG.MR.REPORT] -} - -#[repr(C)] -pub struct qgs_msg_header { - major_version: u16, // TDX major version - minor_version: u16, // TDX minor version - msg_type: u32, // GET_QUOTE_REQ or GET_QUOTE_RESP - size: u32, // size of the whole message, include this header, in byte - error_code: u32, // used in response only -} - -#[repr(C)] -pub struct qgs_msg_get_quote_req { - header: qgs_msg_header, // header.type = GET_QUOTE_REQ - report_size: u32, // cannot be 0 - id_list_size: u32, // length of id_list, in byte, can be 0 - report_id_list: [u8; TDX_REPORT_LEN as usize], // report followed by id list -} - -#[repr(C)] -pub struct tdx_quote_hdr { - version: u64, // Quote version, filled by TD - status: u64, // Status code of Quote request, filled by VMM - in_len: u32, // Length of TDREPORT, filled by TD - out_len: u32, // Length of Quote, filled by VMM - data_len_be_bytes: [u8; 4], // big-endian 4 bytes indicate the size of data following - data: [u8; TDX_QUOTE_LEN as usize], // Actual Quote data or TDREPORT on input -} - -#[repr(C)] -pub struct tdx_quote_req { - buf: u64, // Pass user data that includes TDREPORT as input. Upon successful completion of IOCTL, output is copied back to the same buffer - len: u64, // Length of the Quote buffer -} - -#[repr(C)] -pub struct qgs_msg_get_quote_resp { - header: qgs_msg_header, // header.type = GET_QUOTE_RESP - selected_id_size: u32, // can be 0 in case only one id is sent in request - quote_size: u32, // length of quote_data, in byte - id_quote: [u8; TDX_QUOTE_LEN], // selected id followed by quote -} - -pub enum TdxVersion { - TDX_1_0, - TDX_1_5, -} - -pub enum TdxOperation { - TDX_GET_TD_REPORT = 1, - TDX_1_0_GET_QUOTE = 2, - TDX_1_5_GET_QUOTE = 4, -} - -const REPORT_DATA_LEN: u32 = 64; -const TDX_REPORT_LEN: u32 = 1024; -const TDX_QUOTE_LEN: usize = 4 * 4096; - -pub struct TdxInfo { - tdx_version: TdxVersion, - device_node: File, -} - -impl TdxInfo { - fn new(_tdx_version: TdxVersion, _device_node: File) -> Self { - TdxInfo { - tdx_version: _tdx_version, - device_node: _device_node, - } - } -} - -fn get_tdx_version() -> TdxVersion { - if Path::new("/dev/tdx-guest").exists() { - TdxVersion::TDX_1_0 - } else if Path::new("/dev/tdx_guest").exists() { - TdxVersion::TDX_1_5 - } else if Path::new("/dev/tdx-attest").exists() { - panic!("get_tdx_version: Deprecated device node /dev/tdx-attest, please upgrade to use /dev/tdx-guest or /dev/tdx_guest"); - } else { - panic!("get_tdx_version: no TDX device found!"); - } -} - -pub fn get_td_report(report_data: String) -> Result, anyhow::Error> { - //detect TDX version - let tdx_info = match get_tdx_version() { - TdxVersion::TDX_1_0 => { - let device_node = match File::options() - .read(true) - .write(true) - .open("/dev/tdx-guest") - { - Err(e) => { - return Err(anyhow!( - "[get_td_report] Fail to open {}: {:?}", - "/dev/tdx-guest", - e - )) - } - Ok(fd) => fd, - }; - TdxInfo::new(TdxVersion::TDX_1_0, device_node) - } - TdxVersion::TDX_1_5 => { - let device_node = match File::options() - .read(true) - .write(true) - .open("/dev/tdx_guest") - { - Err(e) => { - return Err(anyhow!( - "[get_td_report] Fail to open {}: {:?}", - "/dev/tdx_guest", - e - )) - } - Ok(fd) => fd, - }; - TdxInfo::new(TdxVersion::TDX_1_5, device_node) - } - }; - - match tdx_info.tdx_version { - TdxVersion::TDX_1_0 => match get_tdx_1_0_report(tdx_info.device_node, report_data) { - Err(e) => return Err(anyhow!("[get_td_report] Fail to get TDX report: {:?}", e)), - Ok(report) => Ok(report), - }, - TdxVersion::TDX_1_5 => match get_tdx_1_5_report(tdx_info.device_node, report_data) { - Err(e) => return Err(anyhow!("[get_td_report] Fail to get TDX report: {:?}", e)), - Ok(report) => Ok(report), - }, - } -} - -fn get_tdx_1_0_report(device_node: File, report_data: String) -> Result, anyhow::Error> { - let report_data_bytes = match base64::decode(report_data) { - Ok(v) => v, - Err(e) => return Err(anyhow!("report data is not base64 encoded: {:?}", e)), - }; - - //prepare get TDX report request data - let mut report_data_array: [u8; REPORT_DATA_LEN as usize] = [0; REPORT_DATA_LEN as usize]; - report_data_array.copy_from_slice(&report_data_bytes[0..]); - let td_report: [u8; TDX_REPORT_LEN as usize] = [0; TDX_REPORT_LEN as usize]; - - //build the request - let request = tdx_1_0_report_req { - subtype: 0 as u8, - reportdata: ptr::addr_of!(report_data_array) as u64, - rpd_len: REPORT_DATA_LEN, - tdreport: ptr::addr_of!(td_report) as u64, - tdr_len: TDX_REPORT_LEN, - }; - - //build the operator code - ioctl_readwrite!( - get_report_1_0_ioctl, - b'T', - TdxOperation::TDX_GET_TD_REPORT, - u64 - ); - - //apply the ioctl command - match unsafe { - get_report_1_0_ioctl(device_node.as_raw_fd(), ptr::addr_of!(request) as *mut u64) - } { - Err(e) => { - return Err(anyhow!( - "[get_tdx_1_0_report] Fail to get TDX report: {:?}", - e - )) - } - Ok(_) => (), - }; - - Ok(td_report.to_vec()) -} - -fn get_tdx_1_5_report(device_node: File, report_data: String) -> Result, anyhow::Error> { - let report_data_bytes = match base64::decode(report_data) { - Ok(v) => v, - Err(e) => return Err(anyhow!("report data is not base64 encoded: {:?}", e)), - }; - - //prepare get TDX report request data - let mut request = tdx_1_5_report_req { - reportdata: [0; REPORT_DATA_LEN as usize], - tdreport: [0; TDX_REPORT_LEN as usize], - }; - request.reportdata.copy_from_slice(&report_data_bytes[0..]); - - //build the operator code - ioctl_readwrite!( - get_report_1_5_ioctl, - b'T', - TdxOperation::TDX_GET_TD_REPORT, - tdx_1_5_report_req - ); - - //apply the ioctl command - match unsafe { - get_report_1_5_ioctl( - device_node.as_raw_fd(), - ptr::addr_of!(request) as *mut tdx_1_5_report_req, - ) - } { - Err(e) => { - return Err(anyhow!( - "[get_tdx_1_5_report] Fail to get TDX report: {:?}", - e - )) - } - Ok(_) => (), - }; - - Ok(request.tdreport.to_vec()) -} - -fn generate_qgs_quote_msg(report: [u8; TDX_REPORT_LEN as usize]) -> qgs_msg_get_quote_req { - //build quote service message header to be used by QGS - let qgs_header = qgs_msg_header { - major_version: 1, - minor_version: 0, - msg_type: 0, - size: 16 + 8 + TDX_REPORT_LEN, // header + report_size and id_list_size + TDX_REPORT_LEN - error_code: 0, - }; - - //build quote service message body to be used by QGS - let mut qgs_request = qgs_msg_get_quote_req { - header: qgs_header, - report_size: TDX_REPORT_LEN, - id_list_size: 0, - report_id_list: [0; TDX_REPORT_LEN as usize], - }; - - qgs_request.report_id_list.copy_from_slice(&report[0..]); - - qgs_request -} - -pub fn get_tdx_quote(report_data: String) -> Result, anyhow::Error> { - //retrieve TDX report - let report_data_vec = match get_td_report(report_data) { - Err(e) => return Err(anyhow!("[get_tdx_quote] Fail to get TDX report: {:?}", e)), - Ok(report) => report, - }; - let report_data_array: [u8; TDX_REPORT_LEN as usize] = match report_data_vec.try_into() { - Ok(r) => r, - Err(e) => return Err(anyhow!("[get_tdx_quote] Wrong TDX report format: {:?}", e)), - }; - - //build QGS request message - let qgs_msg = generate_qgs_quote_msg(report_data_array); - - let tdx_info = match get_tdx_version() { - TdxVersion::TDX_1_0 => { - let device_node = match File::options() - .read(true) - .write(true) - .open("/dev/tdx-guest") - { - Err(e) => { - return Err(anyhow!( - "[get_tdx_quote] Fail to open {}: {:?}", - "/dev/tdx-guest", - e - )) - } - Ok(fd) => fd, - }; - TdxInfo::new(TdxVersion::TDX_1_0, device_node) - } - TdxVersion::TDX_1_5 => { - let device_node = match File::options() - .read(true) - .write(true) - .open("/dev/tdx_guest") - { - Err(e) => { - return Err(anyhow!( - "[get_tdx_quote] Fail to open {}: {:?}", - "/dev/tdx_guest", - e - )) - } - Ok(fd) => fd, - }; - TdxInfo::new(TdxVersion::TDX_1_5, device_node) - } - }; - - //build quote generation request header - let mut quote_header = tdx_quote_hdr { - version: 1, - status: 0, - in_len: (mem::size_of_val(&qgs_msg) + 4) as u32, - out_len: 0, - data_len_be_bytes: (1048 as u32).to_be_bytes(), - data: [0; TDX_QUOTE_LEN as usize], - }; - - let qgs_msg_bytes = unsafe { - let ptr = &qgs_msg as *const qgs_msg_get_quote_req as *const u8; - std::slice::from_raw_parts(ptr, mem::size_of::()) - }; - quote_header.data[0..(16 + 8 + TDX_REPORT_LEN) as usize] - .copy_from_slice(&qgs_msg_bytes[0..((16 + 8 + TDX_REPORT_LEN) as usize)]); - - let request = tdx_quote_req { - buf: ptr::addr_of!(quote_header) as u64, - len: TDX_QUOTE_LEN as u64, - }; - - //build the operator code and apply the ioctl command - match tdx_info.tdx_version { - TdxVersion::TDX_1_0 => { - ioctl_read!( - get_quote_1_0_ioctl, - b'T', - TdxOperation::TDX_1_0_GET_QUOTE, - u64 - ); - match unsafe { - get_quote_1_0_ioctl( - tdx_info.device_node.as_raw_fd(), - ptr::addr_of!(request) as *mut u64, - ) - } { - Err(e) => return Err(anyhow!("[get_tdx_quote] Fail to get TDX quote: {:?}", e)), - Ok(_r) => _r, - }; - } - TdxVersion::TDX_1_5 => { - ioctl_read!( - get_quote_1_5_ioctl, - b'T', - TdxOperation::TDX_1_5_GET_QUOTE, - tdx_quote_req - ); - match unsafe { - get_quote_1_5_ioctl( - tdx_info.device_node.as_raw_fd(), - ptr::addr_of!(request) as *mut tdx_quote_req, - ) - } { - Err(e) => return Err(anyhow!("[get_tdx_quote] Fail to get TDX quote: {:?}", e)), - Ok(_r) => _r, - }; - } - }; - - //inspect the response and retrive quote data - let out_len = quote_header.out_len; - let qgs_msg_resp_size = - unsafe { std::mem::transmute::<[u8; 4], u32>(quote_header.data_len_be_bytes) }.to_be(); - - let qgs_msg_resp = unsafe { - let raw_ptr = ptr::addr_of!(quote_header.data) as *mut qgs_msg_get_quote_resp; - raw_ptr.as_mut().unwrap() as &mut qgs_msg_get_quote_resp - }; - - if out_len - qgs_msg_resp_size != 4 { - return Err(anyhow!( - "[get_tdx_quote] Fail to get TDX quote: wrong TDX quote size!" - )); - } - - if qgs_msg_resp.header.major_version != 1 - || qgs_msg_resp.header.minor_version != 0 - || qgs_msg_resp.header.msg_type != 1 - || qgs_msg_resp.header.error_code != 0 - { - return Err(anyhow!( - "[get_tdx_quote] Fail to get TDX quote: QGS response error!" - )); - } - - Ok(qgs_msg_resp.id_quote[0..(qgs_msg_resp.quote_size as usize)].to_vec()) -} - -#[cfg(test)] -mod tdx_attest_tests { - use super::*; - - #[test] - //TDX ENV required: call get_td_report and verify report data embedded in quote - fn get_td_report_verify_report_data() { - let report_data = "XUccU3O9poJXiX53jNGj1w2v4WVAw8TKDyWm8Y0xgJ2khEMyCSCiWfO/sYMEn5xoC8ES2VzXwmKRv9NVu3YnUA=="; - let report = get_td_report(report_data.to_string()).unwrap(); - - let expected_report_data = [ - 93, 71, 28, 83, 115, 189, 166, 130, 87, 137, 126, 119, 140, 209, 163, 215, 13, 175, - 225, 101, 64, 195, 196, 202, 15, 37, 166, 241, 141, 49, 128, 157, 164, 132, 67, 50, 9, - 32, 162, 89, 243, 191, 177, 131, 4, 159, 156, 104, 11, 193, 18, 217, 92, 215, 194, 98, - 145, 191, 211, 85, 187, 118, 39, 80, - ]; - - let mut report_data_in_report: [u8; 64 as usize] = [0; 64 as usize]; - report_data_in_report.copy_from_slice(&report[128..192]); - assert_eq!(report_data_in_report, expected_report_data); - } - - #[test] - //TDX ENV required: call tdx_get_quote and verify report data embedded in quote - fn get_tdx_quote_verify_report_data() { - let report_data = "XUccU3O9poJXiX53jNGj1w2v4WVAw8TKDyWm8Y0xgJ2khEMyCSCiWfO/sYMEn5xoC8ES2VzXwmKRv9NVu3YnUA=="; - let quote = get_tdx_quote(report_data.to_string()).unwrap(); - - let expected_report_data = [ - 93, 71, 28, 83, 115, 189, 166, 130, 87, 137, 126, 119, 140, 209, 163, 215, 13, 175, - 225, 101, 64, 195, 196, 202, 15, 37, 166, 241, 141, 49, 128, 157, 164, 132, 67, 50, 9, - 32, 162, 89, 243, 191, 177, 131, 4, 159, 156, 104, 11, 193, 18, 217, 92, 215, 194, 98, - 145, 191, 211, 85, 187, 118, 39, 80, - ]; - - let mut report_data_in_quote: [u8; 64 as usize] = [0; 64 as usize]; - report_data_in_quote.copy_from_slice("e[568..632]); - assert_eq!(report_data_in_quote, expected_report_data); - } -}