feat(dcap): use tcbinfo
from contract for RA verification (#179)
Co-authored-by: hu55a1n1 <sufialhussaini@gmail.com>
This commit is contained in:
parent
e7cd6b1151
commit
1a2ab7d008
12 changed files with 123 additions and 15 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -4145,12 +4145,14 @@ dependencies = [
|
|||
"cosmwasm-schema",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"hex",
|
||||
"k256",
|
||||
"quartz-tee-ra",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"sha2 0.10.8",
|
||||
"tcbinfo",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
|
27
apps/mtcs/contracts/cw-tee-mtcs/Cargo.lock
generated
27
apps/mtcs/contracts/cw-tee-mtcs/Cargo.lock
generated
|
@ -771,6 +771,7 @@ dependencies = [
|
|||
"ff",
|
||||
"generic-array",
|
||||
"group",
|
||||
"pem-rfc7468",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"sec1",
|
||||
|
@ -858,6 +859,7 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
|||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1208,12 +1210,14 @@ dependencies = [
|
|||
"cosmwasm-schema",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"hex",
|
||||
"k256",
|
||||
"quartz-tee-ra",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"sha2",
|
||||
"tcbinfo",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
|
@ -1565,6 +1569,29 @@ dependencies = [
|
|||
"syn 2.0.76",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tcbinfo"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"cosmwasm-schema",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"cw2",
|
||||
"der",
|
||||
"getrandom",
|
||||
"hashbrown 0.14.5",
|
||||
"hex",
|
||||
"mc-attestation-verifier",
|
||||
"p256",
|
||||
"quartz-tee-ra",
|
||||
"schemars",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"x509-cert",
|
||||
"x509-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.63"
|
||||
|
|
|
@ -183,7 +183,8 @@ mod tests {
|
|||
"trusting_period": 1209600,
|
||||
"max_clock_drift": 5,
|
||||
"max_block_lag": 5
|
||||
}
|
||||
},
|
||||
"tcbinfo_contract": "wasm14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s0phg4d"
|
||||
}
|
||||
},
|
||||
"attestation": {
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::net::SocketAddr;
|
|||
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use cosmrs::tendermint::Hash;
|
||||
use cosmrs::{tendermint::Hash, AccountId};
|
||||
use tendermint_light_client::types::{Height, TrustThreshold};
|
||||
|
||||
fn parse_trust_threshold(s: &str) -> Result<TrustThreshold> {
|
||||
|
@ -26,6 +26,10 @@ pub struct Cli {
|
|||
#[clap(long)]
|
||||
pub chain_id: String,
|
||||
|
||||
/// TcbInfo contract address
|
||||
#[clap(long)]
|
||||
pub tcbinfo_contract: AccountId,
|
||||
|
||||
/// Height of the trusted header (AKA root-of-trust)
|
||||
#[clap(long)]
|
||||
pub trusted_height: Height,
|
||||
|
|
|
@ -61,6 +61,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
attestor.mr_enclave()?,
|
||||
Duration::from_secs(30 * 24 * 60),
|
||||
light_client_opts,
|
||||
args.tcbinfo_contract.to_string(),
|
||||
);
|
||||
|
||||
let sk = Arc::new(Mutex::new(None));
|
||||
|
|
1
apps/transfers/contracts/Cargo.lock
generated
1
apps/transfers/contracts/Cargo.lock
generated
|
@ -1189,6 +1189,7 @@ dependencies = [
|
|||
"cosmwasm-schema",
|
||||
"cosmwasm-std",
|
||||
"cw-storage-plus",
|
||||
"hex",
|
||||
"k256",
|
||||
"quartz-tee-ra",
|
||||
"serde",
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::{env, net::SocketAddr};
|
|||
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use cosmrs::tendermint::Hash;
|
||||
use cosmrs::{tendermint::Hash, AccountId};
|
||||
use tendermint_light_client::types::{Height, TrustThreshold};
|
||||
|
||||
fn parse_trust_threshold(s: &str) -> Result<TrustThreshold> {
|
||||
|
@ -26,6 +26,10 @@ pub struct Cli {
|
|||
#[clap(long)]
|
||||
pub chain_id: String,
|
||||
|
||||
/// TcbInfo contract address
|
||||
#[clap(long)]
|
||||
pub tcbinfo_contract: AccountId,
|
||||
|
||||
/// Height of the trusted header (AKA root-of-trust)
|
||||
#[clap(long)]
|
||||
pub trusted_height: Height,
|
||||
|
|
|
@ -61,6 +61,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
attestor.mr_enclave()?,
|
||||
Duration::from_secs(30 * 24 * 60),
|
||||
light_client_opts,
|
||||
args.tcbinfo_contract.to_string(),
|
||||
);
|
||||
|
||||
let sk = Arc::new(Mutex::new(None));
|
||||
|
|
|
@ -22,7 +22,7 @@ serde_json.workspace = true
|
|||
serde_with.workspace = true
|
||||
sha2.workspace = true
|
||||
thiserror.workspace = true
|
||||
|
||||
hex.workspace = true
|
||||
# cosmos
|
||||
cw-storage-plus.workspace = true
|
||||
cosmwasm-schema.workspace = true
|
||||
|
@ -31,5 +31,8 @@ cosmwasm-std.workspace = true
|
|||
# quartz
|
||||
quartz-tee-ra.workspace = true
|
||||
|
||||
# tcbinfo
|
||||
tcbinfo = { path = "../tcbinfo", features = ["library"] }
|
||||
|
||||
[dev-dependencies]
|
||||
serde_json.workspace = true
|
||||
|
|
|
@ -13,6 +13,10 @@ pub enum Error {
|
|||
K256(K256Error),
|
||||
#[error("invalid session nonce or attempt to reset pub_key")]
|
||||
BadSessionTransition,
|
||||
#[error("Invalid FMSPC: {0}")]
|
||||
InvalidFmspc(String),
|
||||
#[error("TCB Info query error: {0}")]
|
||||
TcbInfoQueryError(String),
|
||||
}
|
||||
|
||||
impl From<K256Error> for Error {
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||
use quartz_tee_ra::{
|
||||
intel_sgx::dcap::TrustedMrEnclaveIdentity, verify_dcap_attestation, verify_epid_attestation,
|
||||
Error as RaVerificationError,
|
||||
use cosmwasm_std::{
|
||||
from_json, to_json_binary, Binary, Deps, DepsMut, Env, MessageInfo, QueryRequest, Response,
|
||||
WasmQuery,
|
||||
};
|
||||
use quartz_tee_ra::{
|
||||
intel_sgx::dcap::{Collateral, TrustedMrEnclaveIdentity},
|
||||
verify_dcap_attestation, verify_epid_attestation, Error as RaVerificationError,
|
||||
};
|
||||
use tcbinfo::msg::{GetTcbInfoResponse, QueryMsg as TcbInfoQueryMsg};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
|
@ -14,6 +18,28 @@ use crate::{
|
|||
state::CONFIG,
|
||||
};
|
||||
|
||||
pub fn query_tcbinfo(deps: Deps<'_>, fmspc: String) -> Result<Binary, Error> {
|
||||
let config = CONFIG.load(deps.storage).map_err(Error::Std)?;
|
||||
let tcbinfo_addr = config.tcb_info();
|
||||
|
||||
let fmspc_bytes =
|
||||
hex::decode(&fmspc).map_err(|_| Error::InvalidFmspc("Invalid FMSPC format".to_string()))?;
|
||||
if fmspc_bytes.len() != 6 {
|
||||
return Err(Error::InvalidFmspc("FMSPC must be 6 bytes".to_string()));
|
||||
}
|
||||
|
||||
let query_msg = TcbInfoQueryMsg::GetTcbInfo { fmspc };
|
||||
|
||||
let request = QueryRequest::Wasm(WasmQuery::Smart {
|
||||
contract_addr: tcbinfo_addr,
|
||||
msg: to_json_binary(&query_msg).map_err(Error::Std)?,
|
||||
});
|
||||
|
||||
deps.querier
|
||||
.query(&request)
|
||||
.map_err(|err| Error::TcbInfoQueryError(err.to_string()))
|
||||
}
|
||||
|
||||
impl Handler for EpidAttestation {
|
||||
fn handle(
|
||||
self,
|
||||
|
@ -33,17 +59,37 @@ impl Handler for EpidAttestation {
|
|||
}
|
||||
|
||||
impl Handler for DcapAttestation {
|
||||
fn handle(
|
||||
self,
|
||||
_deps: DepsMut<'_>,
|
||||
_env: &Env,
|
||||
_info: &MessageInfo,
|
||||
) -> Result<Response, Error> {
|
||||
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
|
||||
let (quote, collateral) = self.clone().into_tuple();
|
||||
let mr_enclave = TrustedMrEnclaveIdentity::new(self.mr_enclave().into(), [""; 0], [""; 0]);
|
||||
|
||||
// Retrieve the FMSPC from the collateral
|
||||
let fmspc_hex = collateral.tcb_info().to_string();
|
||||
|
||||
// Query the tcbinfo contract with the FMSPC retrieved and validated
|
||||
let tcb_info_query = query_tcbinfo(deps.as_ref(), fmspc_hex)?;
|
||||
let tcb_info_response: GetTcbInfoResponse = from_json(tcb_info_query)?;
|
||||
|
||||
// Serialize the existing collateral
|
||||
let mut collateral_json: serde_json::Value =
|
||||
serde_json::to_value(&collateral).map_err(|e| {
|
||||
Error::TcbInfoQueryError(format!("Failed to serialize collateral: {}", e))
|
||||
})?;
|
||||
|
||||
// Update the tcb_info in the serialized data
|
||||
collateral_json["tcb_info"] = tcb_info_response.tcb_info;
|
||||
|
||||
// Deserialize back into a Collateral
|
||||
let updated_collateral: Collateral =
|
||||
serde_json::from_value(collateral_json).map_err(|e| {
|
||||
Error::TcbInfoQueryError(format!("Failed to deserialize updated collateral: {}", e))
|
||||
})?;
|
||||
|
||||
// attestation handler MUST verify that the user_data and mr_enclave match the config/msg
|
||||
let verification_output =
|
||||
verify_dcap_attestation(quote, updated_collateral, &[mr_enclave.into()]);
|
||||
|
||||
// attestation handler MUST verify that the user_data and mr_enclave match the config/msg
|
||||
let verification_output = verify_dcap_attestation(quote, collateral, &[mr_enclave.into()]);
|
||||
if verification_output.is_success().into() {
|
||||
Ok(Response::default())
|
||||
} else {
|
||||
|
|
|
@ -17,6 +17,7 @@ pub struct Config {
|
|||
mr_enclave: MrEnclave,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: LightClientOpts,
|
||||
tcbinfo_contract: String,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
|
@ -24,11 +25,13 @@ impl Config {
|
|||
mr_enclave: MrEnclave,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: LightClientOpts,
|
||||
tcbinfo_contract: String,
|
||||
) -> Self {
|
||||
Self {
|
||||
mr_enclave,
|
||||
epoch_duration,
|
||||
light_client_opts,
|
||||
tcbinfo_contract,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,6 +42,10 @@ impl Config {
|
|||
pub fn mr_enclave(&self) -> MrEnclave {
|
||||
self.mr_enclave
|
||||
}
|
||||
|
||||
pub fn tcbinfo_contract(&self) -> &str {
|
||||
&self.tcbinfo_contract
|
||||
}
|
||||
}
|
||||
|
||||
#[cw_serde]
|
||||
|
@ -46,12 +53,17 @@ pub struct RawConfig {
|
|||
mr_enclave: HexBinary,
|
||||
epoch_duration: Duration,
|
||||
light_client_opts: RawLightClientOpts,
|
||||
tcbinfo_contract: String,
|
||||
}
|
||||
|
||||
impl RawConfig {
|
||||
pub fn mr_enclave(&self) -> &[u8] {
|
||||
self.mr_enclave.as_slice()
|
||||
}
|
||||
|
||||
pub fn tcb_info(&self) -> String {
|
||||
self.tcbinfo_contract.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<RawConfig> for Config {
|
||||
|
@ -65,6 +77,7 @@ impl TryFrom<RawConfig> for Config {
|
|||
.light_client_opts
|
||||
.try_into()
|
||||
.map_err(|e| StdError::parse_err("light_client_opts", e))?,
|
||||
tcbinfo_contract: value.tcbinfo_contract,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +88,7 @@ impl From<Config> for RawConfig {
|
|||
mr_enclave: value.mr_enclave.into(),
|
||||
epoch_duration: value.epoch_duration,
|
||||
light_client_opts: value.light_client_opts.into(),
|
||||
tcbinfo_contract: value.tcbinfo_contract,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue