From 0f80fad0ce0cb692a5ed1d769963244db78fcc71 Mon Sep 17 00:00:00 2001 From: Xynnn007 Date: Sun, 10 Sep 2023 19:20:17 +0800 Subject: [PATCH] cdh/hub: add unwrap key API for hub binary Signed-off-by: Xynnn007 --- confidential-data-hub/hub/Cargo.toml | 3 +- confidential-data-hub/hub/protos/api.proto | 12 + .../hub/src/bin/confidential-data-hub/api.rs | 257 +++++++++++++++++- .../bin/confidential-data-hub/api_ttrpc.rs | 48 ++++ .../hub/src/bin/confidential-data-hub/main.rs | 10 +- .../src/bin/confidential-data-hub/server.rs | 90 ------ .../confidential-data-hub/server/message.rs | 89 ++++++ .../bin/confidential-data-hub/server/mod.rs | 153 +++++++++++ 8 files changed, 564 insertions(+), 98 deletions(-) delete mode 100644 confidential-data-hub/hub/src/bin/confidential-data-hub/server.rs create mode 100644 confidential-data-hub/hub/src/bin/confidential-data-hub/server/message.rs create mode 100644 confidential-data-hub/hub/src/bin/confidential-data-hub/server/mod.rs diff --git a/confidential-data-hub/hub/Cargo.toml b/confidential-data-hub/hub/Cargo.toml index db21cede3..5eed01edb 100644 --- a/confidential-data-hub/hub/Cargo.toml +++ b/confidential-data-hub/hub/Cargo.toml @@ -21,6 +21,7 @@ lazy_static.workspace = true log.workspace = true protobuf = { workspace = true, optional = true } secret.path = "../secret" +serde = { workspace = true, optional = true } serde_json.workspace = true sev = { path = "../../attestation-agent/deps/sev", optional = true } thiserror.workspace = true @@ -42,4 +43,4 @@ kbs = ["image/kbs", "kms/kbs", "secret/kbs"] # support sev to provide confidential resources sev = ["image/sev", "kms/sev", "dep:sev", "secret/sev"] -bin = ["anyhow", "clap", "protobuf", "tokio/signal", "ttrpc", "ttrpc-codegen"] +bin = ["anyhow", "clap", "protobuf", "serde", "tokio/signal", "ttrpc", "ttrpc-codegen"] diff --git a/confidential-data-hub/hub/protos/api.proto b/confidential-data-hub/hub/protos/api.proto index cba138287..97a3c6266 100644 --- a/confidential-data-hub/hub/protos/api.proto +++ b/confidential-data-hub/hub/protos/api.proto @@ -18,6 +18,14 @@ message GetResourceResponse { bytes Resource = 1; } +message KeyProviderKeyWrapProtocolInput { + bytes KeyProviderKeyWrapProtocolInput = 1; +} + +message KeyProviderKeyWrapProtocolOutput { + bytes KeyProviderKeyWrapProtocolOutput = 1; +} + service SealedSecretService { rpc UnsealSecret(UnsealSecretInput) returns (UnsealSecretOutput) {}; } @@ -25,3 +33,7 @@ service SealedSecretService { service GetResourceService { rpc GetResource(GetResourceRequest) returns (GetResourceResponse) {}; } + +service KeyProviderService { + rpc UnWrapKey(KeyProviderKeyWrapProtocolInput) returns (KeyProviderKeyWrapProtocolOutput) {}; +} diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs index a15d51523..a58d8c2eb 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/api.rs @@ -513,16 +513,265 @@ impl ::protobuf::reflect::ProtobufValue for GetResourceResponse { type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; } +#[derive(PartialEq,Clone,Default,Debug)] +// @@protoc_insertion_point(message:api.KeyProviderKeyWrapProtocolInput) +pub struct KeyProviderKeyWrapProtocolInput { + // message fields + // @@protoc_insertion_point(field:api.KeyProviderKeyWrapProtocolInput.KeyProviderKeyWrapProtocolInput) + pub KeyProviderKeyWrapProtocolInput: ::std::vec::Vec, + // special fields + // @@protoc_insertion_point(special_field:api.KeyProviderKeyWrapProtocolInput.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a KeyProviderKeyWrapProtocolInput { + fn default() -> &'a KeyProviderKeyWrapProtocolInput { + ::default_instance() + } +} + +impl KeyProviderKeyWrapProtocolInput { + pub fn new() -> KeyProviderKeyWrapProtocolInput { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "KeyProviderKeyWrapProtocolInput", + |m: &KeyProviderKeyWrapProtocolInput| { &m.KeyProviderKeyWrapProtocolInput }, + |m: &mut KeyProviderKeyWrapProtocolInput| { &mut m.KeyProviderKeyWrapProtocolInput }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "KeyProviderKeyWrapProtocolInput", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for KeyProviderKeyWrapProtocolInput { + const NAME: &'static str = "KeyProviderKeyWrapProtocolInput"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.KeyProviderKeyWrapProtocolInput = is.read_bytes()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if !self.KeyProviderKeyWrapProtocolInput.is_empty() { + my_size += ::protobuf::rt::bytes_size(1, &self.KeyProviderKeyWrapProtocolInput); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if !self.KeyProviderKeyWrapProtocolInput.is_empty() { + os.write_bytes(1, &self.KeyProviderKeyWrapProtocolInput)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> KeyProviderKeyWrapProtocolInput { + KeyProviderKeyWrapProtocolInput::new() + } + + fn clear(&mut self) { + self.KeyProviderKeyWrapProtocolInput.clear(); + self.special_fields.clear(); + } + + fn default_instance() -> &'static KeyProviderKeyWrapProtocolInput { + static instance: KeyProviderKeyWrapProtocolInput = KeyProviderKeyWrapProtocolInput { + KeyProviderKeyWrapProtocolInput: ::std::vec::Vec::new(), + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for KeyProviderKeyWrapProtocolInput { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("KeyProviderKeyWrapProtocolInput").unwrap()).clone() + } +} + +impl ::std::fmt::Display for KeyProviderKeyWrapProtocolInput { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for KeyProviderKeyWrapProtocolInput { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + +#[derive(PartialEq,Clone,Default,Debug)] +// @@protoc_insertion_point(message:api.KeyProviderKeyWrapProtocolOutput) +pub struct KeyProviderKeyWrapProtocolOutput { + // message fields + // @@protoc_insertion_point(field:api.KeyProviderKeyWrapProtocolOutput.KeyProviderKeyWrapProtocolOutput) + pub KeyProviderKeyWrapProtocolOutput: ::std::vec::Vec, + // special fields + // @@protoc_insertion_point(special_field:api.KeyProviderKeyWrapProtocolOutput.special_fields) + pub special_fields: ::protobuf::SpecialFields, +} + +impl<'a> ::std::default::Default for &'a KeyProviderKeyWrapProtocolOutput { + fn default() -> &'a KeyProviderKeyWrapProtocolOutput { + ::default_instance() + } +} + +impl KeyProviderKeyWrapProtocolOutput { + pub fn new() -> KeyProviderKeyWrapProtocolOutput { + ::std::default::Default::default() + } + + fn generated_message_descriptor_data() -> ::protobuf::reflect::GeneratedMessageDescriptorData { + let mut fields = ::std::vec::Vec::with_capacity(1); + let mut oneofs = ::std::vec::Vec::with_capacity(0); + fields.push(::protobuf::reflect::rt::v2::make_simpler_field_accessor::<_, _>( + "KeyProviderKeyWrapProtocolOutput", + |m: &KeyProviderKeyWrapProtocolOutput| { &m.KeyProviderKeyWrapProtocolOutput }, + |m: &mut KeyProviderKeyWrapProtocolOutput| { &mut m.KeyProviderKeyWrapProtocolOutput }, + )); + ::protobuf::reflect::GeneratedMessageDescriptorData::new_2::( + "KeyProviderKeyWrapProtocolOutput", + fields, + oneofs, + ) + } +} + +impl ::protobuf::Message for KeyProviderKeyWrapProtocolOutput { + const NAME: &'static str = "KeyProviderKeyWrapProtocolOutput"; + + fn is_initialized(&self) -> bool { + true + } + + fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::Result<()> { + while let Some(tag) = is.read_raw_tag_or_eof()? { + match tag { + 10 => { + self.KeyProviderKeyWrapProtocolOutput = is.read_bytes()?; + }, + tag => { + ::protobuf::rt::read_unknown_or_skip_group(tag, is, self.special_fields.mut_unknown_fields())?; + }, + }; + } + ::std::result::Result::Ok(()) + } + + // Compute sizes of nested messages + #[allow(unused_variables)] + fn compute_size(&self) -> u64 { + let mut my_size = 0; + if !self.KeyProviderKeyWrapProtocolOutput.is_empty() { + my_size += ::protobuf::rt::bytes_size(1, &self.KeyProviderKeyWrapProtocolOutput); + } + my_size += ::protobuf::rt::unknown_fields_size(self.special_fields.unknown_fields()); + self.special_fields.cached_size().set(my_size as u32); + my_size + } + + fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::Result<()> { + if !self.KeyProviderKeyWrapProtocolOutput.is_empty() { + os.write_bytes(1, &self.KeyProviderKeyWrapProtocolOutput)?; + } + os.write_unknown_fields(self.special_fields.unknown_fields())?; + ::std::result::Result::Ok(()) + } + + fn special_fields(&self) -> &::protobuf::SpecialFields { + &self.special_fields + } + + fn mut_special_fields(&mut self) -> &mut ::protobuf::SpecialFields { + &mut self.special_fields + } + + fn new() -> KeyProviderKeyWrapProtocolOutput { + KeyProviderKeyWrapProtocolOutput::new() + } + + fn clear(&mut self) { + self.KeyProviderKeyWrapProtocolOutput.clear(); + self.special_fields.clear(); + } + + fn default_instance() -> &'static KeyProviderKeyWrapProtocolOutput { + static instance: KeyProviderKeyWrapProtocolOutput = KeyProviderKeyWrapProtocolOutput { + KeyProviderKeyWrapProtocolOutput: ::std::vec::Vec::new(), + special_fields: ::protobuf::SpecialFields::new(), + }; + &instance + } +} + +impl ::protobuf::MessageFull for KeyProviderKeyWrapProtocolOutput { + fn descriptor() -> ::protobuf::reflect::MessageDescriptor { + static descriptor: ::protobuf::rt::Lazy<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::Lazy::new(); + descriptor.get(|| file_descriptor().message_by_package_relative_name("KeyProviderKeyWrapProtocolOutput").unwrap()).clone() + } +} + +impl ::std::fmt::Display for KeyProviderKeyWrapProtocolOutput { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + ::protobuf::text_format::fmt(self, f) + } +} + +impl ::protobuf::reflect::ProtobufValue for KeyProviderKeyWrapProtocolOutput { + type RuntimeType = ::protobuf::reflect::rt::RuntimeTypeMessage; +} + static file_descriptor_proto_data: &'static [u8] = b"\ \n\tapi.proto\x12\x03api\"+\n\x11UnsealSecretInput\x12\x16\n\x06secret\ \x18\x01\x20\x01(\x0cR\x06secret\"2\n\x12UnsealSecretOutput\x12\x1c\n\tp\ laintext\x18\x01\x20\x01(\x0cR\tplaintext\"8\n\x12GetResourceRequest\x12\ \"\n\x0cResourcePath\x18\x01\x20\x01(\tR\x0cResourcePath\"1\n\x13GetReso\ - urceResponse\x12\x1a\n\x08Resource\x18\x01\x20\x01(\x0cR\x08Resource2V\n\ + urceResponse\x12\x1a\n\x08Resource\x18\x01\x20\x01(\x0cR\x08Resource\"k\ + \n\x1fKeyProviderKeyWrapProtocolInput\x12H\n\x1fKeyProviderKeyWrapProtoc\ + olInput\x18\x01\x20\x01(\x0cR\x1fKeyProviderKeyWrapProtocolInput\"n\n\ + \x20KeyProviderKeyWrapProtocolOutput\x12J\n\x20KeyProviderKeyWrapProtoco\ + lOutput\x18\x01\x20\x01(\x0cR\x20KeyProviderKeyWrapProtocolOutput2V\n\ \x13SealedSecretService\x12?\n\x0cUnsealSecret\x12\x16.api.UnsealSecretI\ nput\x1a\x17.api.UnsealSecretOutput2V\n\x12GetResourceService\x12@\n\x0b\ GetResource\x12\x17.api.GetResourceRequest\x1a\x18.api.GetResourceRespon\ - seb\x06proto3\ + se2n\n\x12KeyProviderService\x12X\n\tUnWrapKey\x12$.api.KeyProviderKeyWr\ + apProtocolInput\x1a%.api.KeyProviderKeyWrapProtocolOutputb\x06proto3\ "; /// `FileDescriptorProto` object which was a source for this generated file @@ -540,11 +789,13 @@ pub fn file_descriptor() -> &'static ::protobuf::reflect::FileDescriptor { file_descriptor.get(|| { let generated_file_descriptor = generated_file_descriptor_lazy.get(|| { let mut deps = ::std::vec::Vec::with_capacity(0); - let mut messages = ::std::vec::Vec::with_capacity(4); + let mut messages = ::std::vec::Vec::with_capacity(6); messages.push(UnsealSecretInput::generated_message_descriptor_data()); messages.push(UnsealSecretOutput::generated_message_descriptor_data()); messages.push(GetResourceRequest::generated_message_descriptor_data()); messages.push(GetResourceResponse::generated_message_descriptor_data()); + messages.push(KeyProviderKeyWrapProtocolInput::generated_message_descriptor_data()); + messages.push(KeyProviderKeyWrapProtocolOutput::generated_message_descriptor_data()); let mut enums = ::std::vec::Vec::with_capacity(0); ::protobuf::reflect::GeneratedFileDescriptor::new_generated( file_descriptor_proto(), diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs index 95f1e5b2b..a86192fa2 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/api_ttrpc.rs @@ -117,3 +117,51 @@ pub fn create_get_resource_service(service: Arc Self { + KeyProviderServiceClient { + client, + } + } + + pub async fn un_wrap_key(&self, ctx: ttrpc::context::Context, req: &super::api::KeyProviderKeyWrapProtocolInput) -> ::ttrpc::Result { + let mut cres = super::api::KeyProviderKeyWrapProtocolOutput::new(); + ::ttrpc::async_client_request!(self, ctx, req, "api.KeyProviderService", "UnWrapKey", cres); + } +} + +struct UnWrapKeyMethod { + service: Arc>, +} + +#[async_trait] +impl ::ttrpc::r#async::MethodHandler for UnWrapKeyMethod { + async fn handler(&self, ctx: ::ttrpc::r#async::TtrpcContext, req: ::ttrpc::Request) -> ::ttrpc::Result<::ttrpc::Response> { + ::ttrpc::async_request_handler!(self, ctx, req, api, KeyProviderKeyWrapProtocolInput, un_wrap_key); + } +} + +#[async_trait] +pub trait KeyProviderService: Sync { + async fn un_wrap_key(&self, _ctx: &::ttrpc::r#async::TtrpcContext, _: super::api::KeyProviderKeyWrapProtocolInput) -> ::ttrpc::Result { + Err(::ttrpc::Error::RpcStatus(::ttrpc::get_status(::ttrpc::Code::NOT_FOUND, "/api.KeyProviderService/UnWrapKey is not supported".to_string()))) + } +} + +pub fn create_key_provider_service(service: Arc>) -> HashMap { + let mut ret = HashMap::new(); + let mut methods = HashMap::new(); + let streams = HashMap::new(); + + methods.insert("UnWrapKey".to_string(), + Box::new(UnWrapKeyMethod{service: service.clone()}) as Box); + + ret.insert("api.KeyProviderService".to_string(), ::ttrpc::r#async::Service{ methods, streams }); + ret +} diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs index 1702ee48c..2737c9da3 100644 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/main.rs @@ -6,7 +6,9 @@ use std::{path::Path, sync::Arc}; use anyhow::{Context, Result}; -use api_ttrpc::create_sealed_secret_service; +use api_ttrpc::{ + create_get_resource_service, create_key_provider_service, create_sealed_secret_service, +}; use clap::Parser; use log::info; use server::Server; @@ -16,8 +18,6 @@ use tokio::{ }; use ttrpc::r#async::Server as TtrpcServer; -use crate::api_ttrpc::create_get_resource_service; - mod api; mod api_ttrpc; mod server; @@ -57,11 +57,13 @@ async fn main() -> Result<()> { let sealed_secret_service = ttrpc_service!(create_sealed_secret_service); let get_resource_service = ttrpc_service!(create_get_resource_service); + let key_provider_service = ttrpc_service!(create_key_provider_service); let mut server = TtrpcServer::new() .bind(&cli.socket) .context("cannot bind cdh ttrpc service")? .register_service(sealed_secret_service) - .register_service(get_resource_service); + .register_service(get_resource_service) + .register_service(key_provider_service); server.start().await?; diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/server.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/server.rs deleted file mode 100644 index 336df1ecf..000000000 --- a/confidential-data-hub/hub/src/bin/confidential-data-hub/server.rs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2023 Alibaba Cloud -// -// SPDX-License-Identifier: Apache-2.0 -// - -use std::sync::Arc; - -use anyhow::Result; -use async_trait::async_trait; -use confidential_data_hub::{hub::Hub, DataHub}; -use lazy_static::lazy_static; -use log::debug; -use tokio::sync::RwLock; -use ttrpc::{asynchronous::TtrpcContext, Code, Error, Status}; - -use crate::{ - api::{GetResourceRequest, GetResourceResponse, UnsealSecretInput, UnsealSecretOutput}, - api_ttrpc::{GetResourceService, SealedSecretService}, -}; - -lazy_static! { - static ref HUB: Arc>> = Arc::new(RwLock::new(None)); -} - -pub struct Server; - -impl Server { - async fn init() -> Result<()> { - let mut writer = HUB.write().await; - if writer.is_none() { - let hub = Hub::new().await?; - *writer = Some(hub); - } - - Ok(()) - } - - pub async fn new() -> Result { - Self::init().await?; - Ok(Self) - } -} - -#[async_trait] -impl SealedSecretService for Server { - async fn unseal_secret( - &self, - _ctx: &TtrpcContext, - input: UnsealSecretInput, - ) -> ::ttrpc::Result { - debug!("get new UnsealSecret request"); - let reader = HUB.read().await; - let reader = reader.as_ref().expect("must be initialized"); - let plaintext = reader.unseal_secret(input.secret).await.map_err(|e| { - let mut status = Status::new(); - status.set_code(Code::INTERNAL); - status.set_message(format!("[CDH] [ERROR]: Unseal Secret failed: {e}")); - Error::RpcStatus(status) - })?; - - let mut reply = UnsealSecretOutput::new(); - reply.plaintext = plaintext; - debug!("send back plaintext of the sealed secret"); - Ok(reply) - } -} - -#[async_trait] -impl GetResourceService for Server { - async fn get_resource( - &self, - _ctx: &TtrpcContext, - req: GetResourceRequest, - ) -> ::ttrpc::Result { - debug!("get new GetResource request"); - let reader = HUB.read().await; - let reader = reader.as_ref().expect("must be initialized"); - let resource = reader.get_resource(req.ResourcePath).await.map_err(|e| { - let mut status = Status::new(); - status.set_code(Code::INTERNAL); - status.set_message(format!("[CDH] [ERROR]: Get Resource failed: {e}")); - Error::RpcStatus(status) - })?; - - let mut reply = GetResourceResponse::new(); - reply.Resource = resource; - debug!("send back the resource"); - Ok(reply) - } -} diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/server/message.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/server/message.rs new file mode 100644 index 000000000..196450ea0 --- /dev/null +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/server/message.rs @@ -0,0 +1,89 @@ +// Copyright (c) 2023 Alibaba Cloud +// +// SPDX-License-Identifier: Apache-2.0 +// + +use anyhow::*; +use base64::Engine; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::str; +use std::vec::Vec; + +const ANNOTATION_KEY_NAME: &str = "attestation-agent"; + +#[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)] +pub struct KeyProviderInput { + // Operation is either "keywrap" or "keyunwrap" + // attestation-agent can only handle the case of "keyunwrap" + op: String, + // For attestation-agent, keywrapparams should be empty. + pub keywrapparams: KeyWrapParams, + pub keyunwrapparams: KeyUnwrapParams, +} + +impl KeyProviderInput { + pub fn get_annotation(&self) -> Result> { + let annotation_base64 = self + .keyunwrapparams + .dc + .as_ref() + .and_then(|dc| dc.parameters.get(ANNOTATION_KEY_NAME)) + .and_then(|paras| paras.get(0)) + .ok_or_else(|| anyhow!("Illegal UnwrapKey request: no AnnotationPacket given."))?; + + let engine = base64::engine::general_purpose::STANDARD; + let annotation = engine.decode(annotation_base64)?; + Ok(annotation) + } +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)] +pub struct KeyWrapParams { + // For attestation-agent, ec is null + pub ec: Option, + // For attestation-agent, optsdata is null + pub optsdata: Option, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] +pub struct Ec { + #[serde(rename = "Parameters")] + pub parameters: HashMap>, + #[serde(rename = "DecryptConfig")] + pub decrypt_config: Dc, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Default, Clone)] +pub struct KeyUnwrapParams { + pub dc: Option, + pub annotation: Option, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)] +pub struct Dc { + // Name is expected to be "attestation-agent". + // Values are expected to be base-64 encoded. + #[serde(rename = "Parameters")] + pub parameters: HashMap>, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct KeyWrapOutput { + pub keywrapresults: KeyWrapResults, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct KeyWrapResults { + pub annotation: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct KeyUnwrapOutput { + pub keyunwrapresults: KeyUnwrapResults, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct KeyUnwrapResults { + pub optsdata: Vec, +} diff --git a/confidential-data-hub/hub/src/bin/confidential-data-hub/server/mod.rs b/confidential-data-hub/hub/src/bin/confidential-data-hub/server/mod.rs new file mode 100644 index 000000000..4565ca9de --- /dev/null +++ b/confidential-data-hub/hub/src/bin/confidential-data-hub/server/mod.rs @@ -0,0 +1,153 @@ +// Copyright (c) 2023 Alibaba Cloud +// +// SPDX-License-Identifier: Apache-2.0 +// + +use std::sync::Arc; + +use anyhow::Result; +use async_trait::async_trait; +use confidential_data_hub::{hub::Hub, DataHub}; +use lazy_static::lazy_static; +use log::debug; +use tokio::sync::RwLock; +use ttrpc::{asynchronous::TtrpcContext, Code, Error, Status}; + +use crate::{ + api::{ + GetResourceRequest, GetResourceResponse, KeyProviderKeyWrapProtocolInput, + KeyProviderKeyWrapProtocolOutput, UnsealSecretInput, UnsealSecretOutput, + }, + api_ttrpc::{GetResourceService, KeyProviderService, SealedSecretService}, + server::message::{KeyProviderInput, KeyUnwrapOutput, KeyUnwrapResults}, +}; + +lazy_static! { + static ref HUB: Arc>> = Arc::new(RwLock::new(None)); +} + +mod message; + +pub struct Server; + +impl Server { + async fn init() -> Result<()> { + let mut writer = HUB.write().await; + if writer.is_none() { + let hub = Hub::new().await?; + *writer = Some(hub); + } + + Ok(()) + } + + pub async fn new() -> Result { + Self::init().await?; + Ok(Self) + } +} + +#[async_trait] +impl SealedSecretService for Server { + async fn unseal_secret( + &self, + _ctx: &TtrpcContext, + input: UnsealSecretInput, + ) -> ::ttrpc::Result { + debug!("get new UnsealSecret request"); + let reader = HUB.read().await; + let reader = reader.as_ref().expect("must be initialized"); + let plaintext = reader.unseal_secret(input.secret).await.map_err(|e| { + let mut status = Status::new(); + status.set_code(Code::INTERNAL); + status.set_message(format!("[CDH] [ERROR]: Unseal Secret failed: {e}")); + Error::RpcStatus(status) + })?; + + let mut reply = UnsealSecretOutput::new(); + reply.plaintext = plaintext; + debug!("send back plaintext of the sealed secret"); + Ok(reply) + } +} + +#[async_trait] +impl GetResourceService for Server { + async fn get_resource( + &self, + _ctx: &TtrpcContext, + req: GetResourceRequest, + ) -> ::ttrpc::Result { + debug!("get new GetResource request"); + let reader = HUB.read().await; + let reader = reader.as_ref().expect("must be initialized"); + let resource = reader.get_resource(req.ResourcePath).await.map_err(|e| { + let mut status = Status::new(); + status.set_code(Code::INTERNAL); + status.set_message(format!("[CDH] [ERROR]: Get Resource failed: {e}")); + Error::RpcStatus(status) + })?; + + let mut reply = GetResourceResponse::new(); + reply.Resource = resource; + debug!("send back the resource"); + Ok(reply) + } +} + +#[async_trait] +impl KeyProviderService for Server { + async fn un_wrap_key( + &self, + _ctx: &TtrpcContext, + req: KeyProviderKeyWrapProtocolInput, + ) -> ::ttrpc::Result { + debug!("get new UnWrapKey request"); + let reader = HUB.read().await; + let reader = reader.as_ref().expect("must be initialized"); + let key_provider_input: KeyProviderInput = + serde_json::from_slice(&req.KeyProviderKeyWrapProtocolInput[..]).map_err(|e| { + let mut status = Status::new(); + status.set_code(Code::INTERNAL); + status.set_message(format!("[ERROR] UnwrapKey Parse request failed: {e}")); + Error::RpcStatus(status) + })?; + + let annotation_packet = key_provider_input.get_annotation().map_err(|e| { + let mut status = Status::new(); + status.set_code(Code::INTERNAL); + status.set_message(format!("[ERROR] UnwrapKey Parse request failed: {e}")); + Error::RpcStatus(status) + })?; + + debug!("Call CDH to Unwrap Key..."); + let decrypted_optsdata = reader.unwrap_key(&annotation_packet).await.map_err(|e| { + let mut status = Status::new(); + status.set_code(Code::INTERNAL); + status.set_message(format!("[CDH] [ERROR]: UnwrapKey failed: {e}")); + Error::RpcStatus(status) + })?; + + let mut reply = KeyProviderKeyWrapProtocolOutput::new(); + + // Construct output structure and serialize it as the return value of gRPC + let output_struct = KeyUnwrapOutput { + keyunwrapresults: KeyUnwrapResults { + optsdata: decrypted_optsdata, + }, + }; + + let lek = serde_json::to_vec(&output_struct).map_err(|e| { + let mut status = Status::new(); + status.set_code(Code::INTERNAL); + status.set_message(format!( + "[CDH] [ERROR]: UnwrapKey serialize response failed: {e}" + )); + Error::RpcStatus(status) + })?; + + reply.KeyProviderKeyWrapProtocolOutput = lek; + debug!("send back the resource"); + Ok(reply) + } +}