-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
There are no files selected for viewing
This file was deleted.
This file was deleted.
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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": "..." | ||
} | ||
] | ||
} | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<string, string> extra_info = 7; | ||
} | ||
|
||
message GetCcEventlogResponse { | ||
repeated TcgEventlog event_logs = 1; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Vec<TcgEventlog>>, | ||
} | ||
|
||
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<u32, Error> { | ||
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<u32, Error> { | ||
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<TcgDigest> = 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<TcgDigest> = 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<Vec<TcgEventlog>, 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<u8>, 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<TcgDigest, Error> { | ||
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) | ||
} | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<dyn std::error::Error>> { | ||
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::<CcnpServer<Service>>().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(()) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Agent> = 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<GetDefaultAlgorithmRequest>, | ||
) -> Result<Response<GetDefaultAlgorithmResponse>, 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<GetMeasurementCountRequest>, | ||
) -> Result<Response<GetMeasurementCountResponse>, 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<GetCcMeasurementRequest>, | ||
) -> Result<Response<GetCcMeasurementResponse>, 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<GetCcEventlogRequest>, | ||
) -> Result<Response<GetCcEventlogResponse>, 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<GetCcReportRequest>, | ||
) -> Result<Response<GetCcReportResponse>, 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 })) | ||
} | ||
} |
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.
This file was deleted.