Quartz base impl (#10)
This commit is contained in:
parent
3ffa3fac5e
commit
b4e5f01cd1
26 changed files with 1183 additions and 0 deletions
5
bisenzone-cw-mvp/packages/quartz-cw/.cargo/config
Normal file
5
bisenzone-cw-mvp/packages/quartz-cw/.cargo/config
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
[alias]
|
||||||
|
wasm = "build --release --lib --target wasm32-unknown-unknown"
|
||||||
|
wasm-debug = "build --lib --target wasm32-unknown-unknown"
|
||||||
|
schema = "run --bin schema"
|
||||||
|
|
19
bisenzone-cw-mvp/packages/quartz-cw/Cargo.toml
Normal file
19
bisenzone-cw-mvp/packages/quartz-cw/Cargo.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[package]
|
||||||
|
name = "quartz-cw"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["hu55a1n1 <sufialhussaini@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cw-storage-plus = "1.1.0"
|
||||||
|
cosmwasm-schema = "1.4.0"
|
||||||
|
cosmwasm-std = "1.4.0"
|
||||||
|
k256 = { version = "0.13.2", default-features = false, features = ["ecdsa", "alloc"] }
|
||||||
|
serde = { version = "1.0.188", default-features = false, features = ["derive"] }
|
||||||
|
sha2 = "0.10.8"
|
||||||
|
thiserror = "1.0.57"
|
||||||
|
|
||||||
|
quartz-tee-ra = { path = "../../packages/quartz-tee-ra" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
serde_json = "1.0.113"
|
1
bisenzone-cw-mvp/packages/quartz-cw/README.md
Normal file
1
bisenzone-cw-mvp/packages/quartz-cw/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# Quartz CosmWasm spec
|
22
bisenzone-cw-mvp/packages/quartz-cw/src/error.rs
Normal file
22
bisenzone-cw-mvp/packages/quartz-cw/src/error.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use cosmwasm_std::StdError;
|
||||||
|
use k256::ecdsa::Error as K256Error;
|
||||||
|
use quartz_tee_ra::Error as RaVerificationError;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("{0}")]
|
||||||
|
Std(#[from] StdError),
|
||||||
|
#[error("{0}")]
|
||||||
|
RaVerification(#[from] RaVerificationError),
|
||||||
|
#[error("Not Secp256K1")]
|
||||||
|
K256(K256Error),
|
||||||
|
#[error("invalid session nonce or attempt to reset pub_key")]
|
||||||
|
BadSessionTransition,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<K256Error> for Error {
|
||||||
|
fn from(e: K256Error) -> Self {
|
||||||
|
Self::K256(e)
|
||||||
|
}
|
||||||
|
}
|
208
bisenzone-cw-mvp/packages/quartz-cw/src/handler.rs
Normal file
208
bisenzone-cw-mvp/packages/quartz-cw/src/handler.rs
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
pub mod execute;
|
||||||
|
pub mod instantiate;
|
||||||
|
|
||||||
|
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::msg::HasDomainType;
|
||||||
|
|
||||||
|
pub trait Handler {
|
||||||
|
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RawHandler: HasDomainType {
|
||||||
|
fn handle_raw(
|
||||||
|
self,
|
||||||
|
deps: DepsMut<'_>,
|
||||||
|
env: &Env,
|
||||||
|
info: &MessageInfo,
|
||||||
|
) -> Result<Response, Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RM> RawHandler for RM
|
||||||
|
where
|
||||||
|
RM: HasDomainType,
|
||||||
|
RM::DomainType: Handler,
|
||||||
|
{
|
||||||
|
fn handle_raw(
|
||||||
|
self,
|
||||||
|
deps: DepsMut<'_>,
|
||||||
|
env: &Env,
|
||||||
|
info: &MessageInfo,
|
||||||
|
) -> Result<Response, Error> {
|
||||||
|
let execute: RM::DomainType = self.try_into()?;
|
||||||
|
execute.handle(deps, env, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||||
|
use cosmwasm_std::DepsMut;
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
use crate::handler::Handler;
|
||||||
|
use crate::msg::{HasDomainType, RawExecuteMsg, RawInstantiateMsg};
|
||||||
|
use crate::state::SESSION;
|
||||||
|
|
||||||
|
fn parse_msg<'a, R>(msg_str: &'a str) -> R::DomainType
|
||||||
|
where
|
||||||
|
R: HasDomainType + Deserialize<'a>,
|
||||||
|
{
|
||||||
|
let raw_msg: R =
|
||||||
|
serde_json::from_str(msg_str).expect("deserialization failure for hard-coded RawMsg");
|
||||||
|
raw_msg.try_into().expect("invalid hard-coded RawMsg")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_msg<'a, R>(mut deps: DepsMut<'_>, msg_str: &'a str)
|
||||||
|
where
|
||||||
|
R: HasDomainType + Deserialize<'a>,
|
||||||
|
R::DomainType: Handler,
|
||||||
|
{
|
||||||
|
let msg = parse_msg::<R>(msg_str);
|
||||||
|
let info = mock_info("creator", &[]);
|
||||||
|
let env = mock_env();
|
||||||
|
let res = msg
|
||||||
|
.handle(deps.branch(), &env, &info)
|
||||||
|
.expect("msg handler failure");
|
||||||
|
|
||||||
|
assert_eq!(0, res.messages.len());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instantiate(deps: DepsMut<'_>) {
|
||||||
|
handle_msg::<RawInstantiateMsg>(
|
||||||
|
deps,
|
||||||
|
r#"{
|
||||||
|
"msg": {
|
||||||
|
"mr_enclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb"
|
||||||
|
},
|
||||||
|
"attestation": {
|
||||||
|
"report": {
|
||||||
|
"report": {
|
||||||
|
"id": "5246688123689513540899231107533660789",
|
||||||
|
"timestamp": "2024-02-07T17:06:23.913745",
|
||||||
|
"version": 4,
|
||||||
|
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||||
|
"advisoryURL": "https://security-center.intel.com",
|
||||||
|
"advisoryIDs": [
|
||||||
|
"INTEL-SA-00161",
|
||||||
|
"INTEL-SA-00219",
|
||||||
|
"INTEL-SA-00289",
|
||||||
|
"INTEL-SA-00334",
|
||||||
|
"INTEL-SA-00615"
|
||||||
|
],
|
||||||
|
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||||
|
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||||
|
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||||
|
},
|
||||||
|
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||||
|
},
|
||||||
|
"mr_enclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||||
|
"user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn session_create(deps: DepsMut<'_>) {
|
||||||
|
handle_msg::<RawExecuteMsg>(
|
||||||
|
deps,
|
||||||
|
r#"{
|
||||||
|
"session_create": {
|
||||||
|
"msg": {
|
||||||
|
"nonce": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c2777"
|
||||||
|
},
|
||||||
|
"attestation": {
|
||||||
|
"report": {
|
||||||
|
"report": {
|
||||||
|
"id": "5246688123689513540899231107533660789",
|
||||||
|
"timestamp": "2024-02-07T17:06:23.913745",
|
||||||
|
"version": 4,
|
||||||
|
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||||
|
"advisoryURL": "https://security-center.intel.com",
|
||||||
|
"advisoryIDs": [
|
||||||
|
"INTEL-SA-00161",
|
||||||
|
"INTEL-SA-00219",
|
||||||
|
"INTEL-SA-00289",
|
||||||
|
"INTEL-SA-00334",
|
||||||
|
"INTEL-SA-00615"
|
||||||
|
],
|
||||||
|
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||||
|
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||||
|
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||||
|
},
|
||||||
|
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||||
|
},
|
||||||
|
"mr_enclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||||
|
"user_data": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c27770000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn session_set_pub_key(deps: DepsMut<'_>) {
|
||||||
|
handle_msg::<RawExecuteMsg>(
|
||||||
|
deps,
|
||||||
|
r#"{
|
||||||
|
"session_set_pub_key": {
|
||||||
|
"msg": {
|
||||||
|
"nonce": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c2777"
|
||||||
|
"pub_key": "03E67EF09213633074FB4FBF338643F4F0C574ED60EF11D03422EEB06FA38C8F3F"
|
||||||
|
},
|
||||||
|
"attestation": {
|
||||||
|
"report": {
|
||||||
|
"report": {
|
||||||
|
"id": "5246688123689513540899231107533660789",
|
||||||
|
"timestamp": "2024-02-07T17:06:23.913745",
|
||||||
|
"version": 4,
|
||||||
|
"epidPseudonym": "+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=",
|
||||||
|
"advisoryURL": "https://security-center.intel.com",
|
||||||
|
"advisoryIDs": [
|
||||||
|
"INTEL-SA-00161",
|
||||||
|
"INTEL-SA-00219",
|
||||||
|
"INTEL-SA-00289",
|
||||||
|
"INTEL-SA-00334",
|
||||||
|
"INTEL-SA-00615"
|
||||||
|
],
|
||||||
|
"isvEnclaveQuoteStatus": "CONFIGURATION_AND_SW_HARDENING_NEEDED",
|
||||||
|
"platformInfoBlob": "150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1",
|
||||||
|
"isvEnclaveQuoteBody": "AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||||
|
},
|
||||||
|
"reportsig": "YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="
|
||||||
|
},
|
||||||
|
"mr_enclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||||
|
"user_data": "425d87f8620e1dedeee70590cc55b164b8f01480ee59e0b1da35436a2f7c27770000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_instantiate_handler() {
|
||||||
|
let mut deps = mock_dependencies();
|
||||||
|
instantiate(deps.as_mut());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_session_create_handler() {
|
||||||
|
let mut deps = mock_dependencies();
|
||||||
|
instantiate(deps.as_mut());
|
||||||
|
session_create(deps.as_mut());
|
||||||
|
SESSION.load(&deps.storage).expect("Session not created");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn test_session_set_pub_key_handler() {
|
||||||
|
let mut deps = mock_dependencies();
|
||||||
|
instantiate(deps.as_mut());
|
||||||
|
session_create(deps.as_mut());
|
||||||
|
session_set_pub_key(deps.as_mut());
|
||||||
|
SESSION.load(&deps.storage).expect("Session not created");
|
||||||
|
// TODO(hu55a1n1): check that nonce & pub_key match, etc.
|
||||||
|
}
|
||||||
|
}
|
18
bisenzone-cw-mvp/packages/quartz-cw/src/handler/execute.rs
Normal file
18
bisenzone-cw-mvp/packages/quartz-cw/src/handler/execute.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
pub mod attested;
|
||||||
|
pub mod session_create;
|
||||||
|
pub mod session_set_pub_key;
|
||||||
|
|
||||||
|
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::handler::Handler;
|
||||||
|
use crate::msg::execute::Execute;
|
||||||
|
|
||||||
|
impl Handler for Execute {
|
||||||
|
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error> {
|
||||||
|
match self {
|
||||||
|
Execute::SessionCreate(msg) => msg.handle(deps, env, info),
|
||||||
|
Execute::SessionSetPubKey(msg) => msg.handle(deps, env, info),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||||
|
use quartz_tee_ra::{verify_epid_attestation, Error as RaVerificationError};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::handler::Handler;
|
||||||
|
use crate::msg::execute::attested::{Attestation, Attested, EpidAttestation, HasUserData};
|
||||||
|
use crate::state::CONFIG;
|
||||||
|
|
||||||
|
impl Handler for EpidAttestation {
|
||||||
|
fn handle(
|
||||||
|
self,
|
||||||
|
_deps: DepsMut<'_>,
|
||||||
|
_env: &Env,
|
||||||
|
_info: &MessageInfo,
|
||||||
|
) -> Result<Response, Error> {
|
||||||
|
let (report, mr_enclave, user_data) = self.into_tuple();
|
||||||
|
verify_epid_attestation(report, mr_enclave, user_data)
|
||||||
|
.map(|_| Response::default())
|
||||||
|
.map_err(Error::RaVerification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M, A> Handler for Attested<M, A>
|
||||||
|
where
|
||||||
|
M: Handler + HasUserData,
|
||||||
|
A: Handler + HasUserData + Attestation,
|
||||||
|
{
|
||||||
|
fn handle(
|
||||||
|
self,
|
||||||
|
mut deps: DepsMut<'_>,
|
||||||
|
env: &Env,
|
||||||
|
info: &MessageInfo,
|
||||||
|
) -> Result<Response, Error> {
|
||||||
|
let (msg, attestation) = self.into_tuple();
|
||||||
|
if msg.user_data() != attestation.user_data() {
|
||||||
|
return Err(RaVerificationError::UserDataMismatch.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(config) = CONFIG.may_load(deps.storage)? {
|
||||||
|
// if we weren't able to load then the context was from InstantiateMsg so we don't fail
|
||||||
|
if *config.mr_enclave() != attestation.mr_enclave() {
|
||||||
|
return Err(RaVerificationError::MrEnclaveMismatch.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Handler::handle(attestation, deps.branch(), env, info)?;
|
||||||
|
Handler::handle(msg, deps, env, info)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::handler::Handler;
|
||||||
|
use crate::msg::execute::session_create::SessionCreate;
|
||||||
|
use crate::state::{Session, SESSION};
|
||||||
|
|
||||||
|
impl Handler for SessionCreate {
|
||||||
|
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
|
||||||
|
// TODO(hu55a1n1): overwrite previous session?
|
||||||
|
SESSION
|
||||||
|
.save(deps.storage, &Session::create(self.into_nonce()))
|
||||||
|
.map_err(Error::Std)?;
|
||||||
|
|
||||||
|
Ok(Response::new().add_attribute("action", "session_create"))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
use cosmwasm_std::{DepsMut, Env, HexBinary, MessageInfo, Response};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::handler::Handler;
|
||||||
|
use crate::msg::execute::session_set_pub_key::SessionSetPubKey;
|
||||||
|
use crate::state::SESSION;
|
||||||
|
|
||||||
|
impl Handler for SessionSetPubKey {
|
||||||
|
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
|
||||||
|
let session = SESSION.load(deps.storage).map_err(Error::Std)?;
|
||||||
|
let (nonce, pub_key) = self.into_tuple();
|
||||||
|
let session = session
|
||||||
|
.with_pub_key(nonce, pub_key)
|
||||||
|
.ok_or(Error::BadSessionTransition)?;
|
||||||
|
|
||||||
|
SESSION.save(deps.storage, &session).map_err(Error::Std)?;
|
||||||
|
|
||||||
|
Ok(Response::new()
|
||||||
|
.add_attribute("action", "session_set_pub_key")
|
||||||
|
.add_attribute(
|
||||||
|
"pub_key",
|
||||||
|
HexBinary::from(pub_key.to_sec1_bytes().into_vec()).to_hex(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||||
|
use quartz_tee_ra::Error as RaVerificationError;
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::handler::Handler;
|
||||||
|
use crate::msg::execute::attested::{Attestation, EpidAttestation};
|
||||||
|
use crate::msg::instantiate::{CoreInstantiate, Instantiate};
|
||||||
|
use crate::state::Config;
|
||||||
|
use crate::state::CONFIG;
|
||||||
|
|
||||||
|
impl Handler for Instantiate<EpidAttestation> {
|
||||||
|
fn handle(self, deps: DepsMut<'_>, env: &Env, info: &MessageInfo) -> Result<Response, Error> {
|
||||||
|
if self.0.msg().mr_enclave() != self.0.attestation().mr_enclave() {
|
||||||
|
return Err(RaVerificationError::MrEnclaveMismatch.into());
|
||||||
|
}
|
||||||
|
self.0.handle(deps, env, info)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handler for CoreInstantiate {
|
||||||
|
fn handle(self, deps: DepsMut<'_>, _env: &Env, _info: &MessageInfo) -> Result<Response, Error> {
|
||||||
|
CONFIG
|
||||||
|
.save(deps.storage, &Config::new(self.mr_enclave()))
|
||||||
|
.map_err(Error::Std)?;
|
||||||
|
Ok(Response::new().add_attribute("action", "instantiate"))
|
||||||
|
}
|
||||||
|
}
|
22
bisenzone-cw-mvp/packages/quartz-cw/src/lib.rs
Normal file
22
bisenzone-cw-mvp/packages/quartz-cw/src/lib.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#![warn(
|
||||||
|
clippy::checked_conversions,
|
||||||
|
clippy::panic,
|
||||||
|
clippy::panic_in_result_fn,
|
||||||
|
clippy::unwrap_used,
|
||||||
|
rust_2018_idioms,
|
||||||
|
unused_lifetimes
|
||||||
|
)]
|
||||||
|
#![deny(
|
||||||
|
trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_qualifications,
|
||||||
|
warnings
|
||||||
|
)]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
pub mod handler;
|
||||||
|
pub mod msg;
|
||||||
|
pub mod prelude;
|
||||||
|
pub mod state;
|
12
bisenzone-cw-mvp/packages/quartz-cw/src/msg.rs
Normal file
12
bisenzone-cw-mvp/packages/quartz-cw/src/msg.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
pub mod execute;
|
||||||
|
pub mod instantiate;
|
||||||
|
pub mod query;
|
||||||
|
|
||||||
|
pub use execute::{Execute as ExecuteMsg, RawExecute as RawExecuteMsg};
|
||||||
|
pub use instantiate::{Instantiate as InstantiateMsg, RawInstantiate as RawInstantiateMsg};
|
||||||
|
|
||||||
|
use cosmwasm_std::StdError;
|
||||||
|
|
||||||
|
pub trait HasDomainType: From<Self::DomainType> {
|
||||||
|
type DomainType: TryFrom<Self, Error = StdError>;
|
||||||
|
}
|
63
bisenzone-cw-mvp/packages/quartz-cw/src/msg/execute.rs
Normal file
63
bisenzone-cw-mvp/packages/quartz-cw/src/msg/execute.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
pub mod attested;
|
||||||
|
pub mod session_create;
|
||||||
|
pub mod session_set_pub_key;
|
||||||
|
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::StdError;
|
||||||
|
|
||||||
|
use crate::msg::execute::attested::{Attested, EpidAttestation};
|
||||||
|
use crate::msg::execute::attested::{RawAttested, RawEpidAttestation};
|
||||||
|
use crate::msg::execute::session_create::{RawSessionCreate, SessionCreate};
|
||||||
|
use crate::msg::execute::session_set_pub_key::{RawSessionSetPubKey, SessionSetPubKey};
|
||||||
|
use crate::msg::HasDomainType;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum Execute<Attestation = EpidAttestation> {
|
||||||
|
SessionCreate(Attested<SessionCreate, Attestation>),
|
||||||
|
SessionSetPubKey(Attested<SessionSetPubKey, Attestation>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub enum RawExecute<RawAttestation = RawEpidAttestation> {
|
||||||
|
#[serde(rename = "session_create")]
|
||||||
|
RawSessionCreate(RawAttested<RawSessionCreate, RawAttestation>),
|
||||||
|
#[serde(rename = "session_set_pub_key")]
|
||||||
|
RawSessionSetPubKey(RawAttested<RawSessionSetPubKey, RawAttestation>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RA> TryFrom<RawExecute<RA>> for Execute<RA::DomainType>
|
||||||
|
where
|
||||||
|
RA: HasDomainType,
|
||||||
|
{
|
||||||
|
type Error = StdError;
|
||||||
|
|
||||||
|
fn try_from(value: RawExecute<RA>) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
RawExecute::RawSessionCreate(msg) => {
|
||||||
|
Ok(Execute::SessionCreate(TryFrom::try_from(msg)?))
|
||||||
|
}
|
||||||
|
RawExecute::RawSessionSetPubKey(msg) => {
|
||||||
|
Ok(Execute::SessionSetPubKey(TryFrom::try_from(msg)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RA> From<Execute<RA::DomainType>> for RawExecute<RA>
|
||||||
|
where
|
||||||
|
RA: HasDomainType,
|
||||||
|
{
|
||||||
|
fn from(value: Execute<RA::DomainType>) -> Self {
|
||||||
|
match value {
|
||||||
|
Execute::SessionCreate(msg) => RawExecute::RawSessionCreate(From::from(msg)),
|
||||||
|
Execute::SessionSetPubKey(msg) => RawExecute::RawSessionSetPubKey(From::from(msg)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A> HasDomainType for RawExecute<A>
|
||||||
|
where
|
||||||
|
A: HasDomainType,
|
||||||
|
{
|
||||||
|
type DomainType = Execute<A::DomainType>;
|
||||||
|
}
|
146
bisenzone-cw-mvp/packages/quartz-cw/src/msg/execute/attested.rs
Normal file
146
bisenzone-cw-mvp/packages/quartz-cw/src/msg/execute/attested.rs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::{HexBinary, StdError};
|
||||||
|
use quartz_tee_ra::IASReport;
|
||||||
|
|
||||||
|
use crate::msg::HasDomainType;
|
||||||
|
use crate::state::{MrEnclave, UserData};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Attested<M, A> {
|
||||||
|
msg: M,
|
||||||
|
attestation: A,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M, A> Attested<M, A> {
|
||||||
|
pub fn into_tuple(self) -> (M, A) {
|
||||||
|
let Attested { msg, attestation } = self;
|
||||||
|
(msg, attestation)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn msg(&self) -> &M {
|
||||||
|
&self.msg
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attestation(&self) -> &A {
|
||||||
|
&self.attestation
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct RawAttested<RM, RA> {
|
||||||
|
pub msg: RM,
|
||||||
|
pub attestation: RA,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RM, RA> TryFrom<RawAttested<RM, RA>> for Attested<RM::DomainType, RA::DomainType>
|
||||||
|
where
|
||||||
|
RM: HasDomainType,
|
||||||
|
RA: HasDomainType,
|
||||||
|
{
|
||||||
|
type Error = StdError;
|
||||||
|
|
||||||
|
fn try_from(value: RawAttested<RM, RA>) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self {
|
||||||
|
msg: value.msg.try_into()?,
|
||||||
|
attestation: value.attestation.try_into()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RM, RA> From<Attested<RM::DomainType, RA::DomainType>> for RawAttested<RM, RA>
|
||||||
|
where
|
||||||
|
RM: HasDomainType,
|
||||||
|
RA: HasDomainType,
|
||||||
|
{
|
||||||
|
fn from(value: Attested<RM::DomainType, RA::DomainType>) -> Self {
|
||||||
|
Self {
|
||||||
|
msg: value.msg.into(),
|
||||||
|
attestation: value.attestation.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RM, RA> HasDomainType for RawAttested<RM, RA>
|
||||||
|
where
|
||||||
|
RM: HasDomainType,
|
||||||
|
RA: HasDomainType,
|
||||||
|
{
|
||||||
|
type DomainType = Attested<RM::DomainType, RA::DomainType>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasUserData {
|
||||||
|
fn user_data(&self) -> UserData;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct EpidAttestation {
|
||||||
|
report: IASReport,
|
||||||
|
mr_enclave: MrEnclave,
|
||||||
|
user_data: UserData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EpidAttestation {
|
||||||
|
pub fn into_tuple(self) -> (IASReport, MrEnclave, UserData) {
|
||||||
|
let EpidAttestation {
|
||||||
|
report,
|
||||||
|
mr_enclave,
|
||||||
|
user_data,
|
||||||
|
} = self;
|
||||||
|
(report, mr_enclave, user_data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn report(&self) -> &IASReport {
|
||||||
|
&self.report
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct RawEpidAttestation {
|
||||||
|
report: IASReport,
|
||||||
|
mr_enclave: HexBinary,
|
||||||
|
user_data: HexBinary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<RawEpidAttestation> for EpidAttestation {
|
||||||
|
type Error = StdError;
|
||||||
|
|
||||||
|
fn try_from(value: RawEpidAttestation) -> Result<Self, Self::Error> {
|
||||||
|
let mr_enclave = value.mr_enclave.to_array()?;
|
||||||
|
let user_data = value.user_data.to_array()?;
|
||||||
|
Ok(Self {
|
||||||
|
report: value.report,
|
||||||
|
mr_enclave,
|
||||||
|
user_data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EpidAttestation> for RawEpidAttestation {
|
||||||
|
fn from(value: EpidAttestation) -> Self {
|
||||||
|
Self {
|
||||||
|
report: value.report,
|
||||||
|
mr_enclave: value.mr_enclave.into(),
|
||||||
|
user_data: value.user_data.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasDomainType for RawEpidAttestation {
|
||||||
|
type DomainType = EpidAttestation;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasUserData for EpidAttestation {
|
||||||
|
fn user_data(&self) -> UserData {
|
||||||
|
self.user_data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Attestation {
|
||||||
|
fn mr_enclave(&self) -> MrEnclave;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Attestation for EpidAttestation {
|
||||||
|
fn mr_enclave(&self) -> MrEnclave {
|
||||||
|
self.report().report.isv_enclave_quote_body.mrenclave()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::{HexBinary, StdError};
|
||||||
|
|
||||||
|
use crate::msg::execute::attested::HasUserData;
|
||||||
|
use crate::msg::HasDomainType;
|
||||||
|
use crate::state::{Nonce, UserData};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct SessionCreate {
|
||||||
|
nonce: Nonce,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SessionCreate {
|
||||||
|
pub fn into_nonce(self) -> Nonce {
|
||||||
|
self.nonce
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct RawSessionCreate {
|
||||||
|
nonce: HexBinary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<RawSessionCreate> for SessionCreate {
|
||||||
|
type Error = StdError;
|
||||||
|
|
||||||
|
fn try_from(value: RawSessionCreate) -> Result<Self, Self::Error> {
|
||||||
|
let nonce = value.nonce.to_array()?;
|
||||||
|
Ok(Self { nonce })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SessionCreate> for RawSessionCreate {
|
||||||
|
fn from(value: SessionCreate) -> Self {
|
||||||
|
Self {
|
||||||
|
nonce: value.nonce.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasDomainType for RawSessionCreate {
|
||||||
|
type DomainType = SessionCreate;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasUserData for SessionCreate {
|
||||||
|
fn user_data(&self) -> UserData {
|
||||||
|
let mut user_data = [0u8; 64];
|
||||||
|
user_data[0..32].copy_from_slice(&self.nonce);
|
||||||
|
user_data
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::{HexBinary, StdError};
|
||||||
|
use k256::ecdsa::VerifyingKey;
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
use crate::msg::execute::attested::HasUserData;
|
||||||
|
use crate::msg::HasDomainType;
|
||||||
|
use crate::state::{Nonce, UserData};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct SessionSetPubKey {
|
||||||
|
nonce: Nonce,
|
||||||
|
pub_key: VerifyingKey,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SessionSetPubKey {
|
||||||
|
pub fn into_tuple(self) -> (Nonce, VerifyingKey) {
|
||||||
|
(self.nonce, self.pub_key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct RawSessionSetPubKey {
|
||||||
|
nonce: HexBinary,
|
||||||
|
pub_key: HexBinary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<RawSessionSetPubKey> for SessionSetPubKey {
|
||||||
|
type Error = StdError;
|
||||||
|
|
||||||
|
fn try_from(value: RawSessionSetPubKey) -> Result<Self, Self::Error> {
|
||||||
|
let nonce = value.nonce.to_array()?;
|
||||||
|
let pub_key = VerifyingKey::from_sec1_bytes(&value.pub_key)
|
||||||
|
.map_err(Error::from)
|
||||||
|
.map_err(|e| StdError::generic_err(e.to_string()))?;
|
||||||
|
Ok(Self { nonce, pub_key })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SessionSetPubKey> for RawSessionSetPubKey {
|
||||||
|
fn from(value: SessionSetPubKey) -> Self {
|
||||||
|
Self {
|
||||||
|
nonce: value.nonce.into(),
|
||||||
|
pub_key: value.pub_key.to_sec1_bytes().into_vec().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasDomainType for RawSessionSetPubKey {
|
||||||
|
type DomainType = SessionSetPubKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasUserData for SessionSetPubKey {
|
||||||
|
fn user_data(&self) -> UserData {
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(self.nonce);
|
||||||
|
hasher.update(self.pub_key.to_sec1_bytes());
|
||||||
|
let digest: [u8; 32] = hasher.finalize().into();
|
||||||
|
|
||||||
|
let mut user_data = [0u8; 64];
|
||||||
|
user_data[0..32].copy_from_slice(&digest);
|
||||||
|
user_data
|
||||||
|
}
|
||||||
|
}
|
89
bisenzone-cw-mvp/packages/quartz-cw/src/msg/instantiate.rs
Normal file
89
bisenzone-cw-mvp/packages/quartz-cw/src/msg/instantiate.rs
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::{HexBinary, StdError};
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
use crate::msg::execute::attested::{
|
||||||
|
Attested, EpidAttestation, HasUserData, RawAttested, RawEpidAttestation,
|
||||||
|
};
|
||||||
|
use crate::msg::HasDomainType;
|
||||||
|
use crate::state::{MrEnclave, UserData};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Instantiate<A = EpidAttestation>(pub(crate) Attested<CoreInstantiate, A>);
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct RawInstantiate<RA = RawEpidAttestation>(RawAttested<RawCoreInstantiate, RA>);
|
||||||
|
|
||||||
|
impl<RA> TryFrom<RawInstantiate<RA>> for Instantiate<RA::DomainType>
|
||||||
|
where
|
||||||
|
RA: HasDomainType,
|
||||||
|
{
|
||||||
|
type Error = StdError;
|
||||||
|
|
||||||
|
fn try_from(value: RawInstantiate<RA>) -> Result<Self, Self::Error> {
|
||||||
|
Ok(Self(TryFrom::try_from(value.0)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<RA> From<Instantiate<RA::DomainType>> for RawInstantiate<RA>
|
||||||
|
where
|
||||||
|
RA: HasDomainType,
|
||||||
|
{
|
||||||
|
fn from(value: Instantiate<RA::DomainType>) -> Self {
|
||||||
|
Self(From::from(value.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasDomainType for RawInstantiate {
|
||||||
|
type DomainType = Instantiate;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct CoreInstantiate {
|
||||||
|
mr_enclave: MrEnclave,
|
||||||
|
// TODO(hu55a1n1): config - e.g. Epoch duration, light client opts
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CoreInstantiate {
|
||||||
|
pub fn mr_enclave(&self) -> MrEnclave {
|
||||||
|
self.mr_enclave
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct RawCoreInstantiate {
|
||||||
|
mr_enclave: HexBinary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<RawCoreInstantiate> for CoreInstantiate {
|
||||||
|
type Error = StdError;
|
||||||
|
|
||||||
|
fn try_from(value: RawCoreInstantiate) -> Result<Self, Self::Error> {
|
||||||
|
let mr_enclave = value.mr_enclave.to_array()?;
|
||||||
|
Ok(Self { mr_enclave })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CoreInstantiate> for RawCoreInstantiate {
|
||||||
|
fn from(value: CoreInstantiate) -> Self {
|
||||||
|
Self {
|
||||||
|
mr_enclave: value.mr_enclave.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasDomainType for RawCoreInstantiate {
|
||||||
|
type DomainType = CoreInstantiate;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasUserData for CoreInstantiate {
|
||||||
|
fn user_data(&self) -> UserData {
|
||||||
|
let mut hasher = Sha256::new();
|
||||||
|
hasher.update(self.mr_enclave);
|
||||||
|
let digest: [u8; 32] = hasher.finalize().into();
|
||||||
|
|
||||||
|
let mut user_data = [0u8; 64];
|
||||||
|
user_data[0..32].copy_from_slice(&digest);
|
||||||
|
user_data
|
||||||
|
}
|
||||||
|
}
|
1
bisenzone-cw-mvp/packages/quartz-cw/src/msg/query.rs
Normal file
1
bisenzone-cw-mvp/packages/quartz-cw/src/msg/query.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
3
bisenzone-cw-mvp/packages/quartz-cw/src/prelude.rs
Normal file
3
bisenzone-cw-mvp/packages/quartz-cw/src/prelude.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
pub use crate::handler::RawHandler;
|
||||||
|
pub use crate::msg::execute::RawExecute as QuartzExecuteMsg;
|
||||||
|
pub use crate::msg::instantiate::RawInstantiate as QuartzInstantiateMsg;
|
52
bisenzone-cw-mvp/packages/quartz-cw/src/state.rs
Normal file
52
bisenzone-cw-mvp/packages/quartz-cw/src/state.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::HexBinary;
|
||||||
|
use cw_storage_plus::Item;
|
||||||
|
use k256::ecdsa::VerifyingKey;
|
||||||
|
|
||||||
|
pub type MrEnclave = [u8; 32];
|
||||||
|
pub type Nonce = [u8; 32];
|
||||||
|
pub type UserData = [u8; 64];
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct Config {
|
||||||
|
mr_enclave: HexBinary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn new(mr_enclave: MrEnclave) -> Self {
|
||||||
|
Self {
|
||||||
|
mr_enclave: mr_enclave.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mr_enclave(&self) -> &HexBinary {
|
||||||
|
&self.mr_enclave
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct Session {
|
||||||
|
nonce: HexBinary,
|
||||||
|
pub_key: Option<HexBinary>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Session {
|
||||||
|
pub fn create(nonce: Nonce) -> Self {
|
||||||
|
Self {
|
||||||
|
nonce: nonce.into(),
|
||||||
|
pub_key: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_pub_key(mut self, nonce: Nonce, pub_key: VerifyingKey) -> Option<Self> {
|
||||||
|
if self.nonce == nonce && self.pub_key.is_none() {
|
||||||
|
self.pub_key = Some(pub_key.to_sec1_bytes().into_vec().into());
|
||||||
|
Some(self)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CONFIG: Item<'_, Config> = Item::new("quartz_config");
|
||||||
|
pub const SESSION: Item<'_, Session> = Item::new("quartz_session");
|
15
bisenzone-cw-mvp/packages/quartz-tee-ra/Cargo.toml
Normal file
15
bisenzone-cw-mvp/packages/quartz-tee-ra/Cargo.toml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[package]
|
||||||
|
name = "quartz-tee-ra"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
cosmwasm-schema = "1.4.0"
|
||||||
|
cosmwasm-std = "1.4.0"
|
||||||
|
hex-literal = "0.4.1"
|
||||||
|
num-bigint = "0.4.4"
|
||||||
|
serde_json = "1.0.108"
|
||||||
|
sha2 = "0.10.8"
|
||||||
|
thiserror = { version = "1.0.49" }
|
13
bisenzone-cw-mvp/packages/quartz-tee-ra/src/intel_sgx.rs
Normal file
13
bisenzone-cw-mvp/packages/quartz-tee-ra/src/intel_sgx.rs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub mod epid;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Specified user data does not match the report")]
|
||||||
|
UserDataMismatch,
|
||||||
|
#[error("Specified MRENCLAVE does not match the report")]
|
||||||
|
MrEnclaveMismatch,
|
||||||
|
#[error("EPID specific error: {0}")]
|
||||||
|
Epid(#[from] epid::Error),
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
use hex_literal::hex;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub const INTEL_ROOT_MODULUS: &[u8] = &hex!("a97a2de0e66ea6147c9ee745ac0162686c7192099afc4b3f040fad6de093511d74e802f510d716038157dcaf84f4104bd3fed7e6b8f99c8817fd1ff5b9b864296c3d81fa8f1b729e02d21d72ffee4ced725efe74bea68fbc4d4244286fcdd4bf64406a439a15bcb4cf67754489c423972b4a80df5c2e7c5bc2dbaf2d42bb7b244f7c95bf92c75d3b33fc5410678a89589d1083da3acc459f2704cd99598c275e7c1878e00757e5bdb4e840226c11c0a17ff79c80b15c1ddb5af21cc2417061fbd2a2da819ed3b72b7efaa3bfebe2805c9b8ac19aa346512d484cfc81941e15f55881cc127e8f7aa12300cd5afb5742fa1d20cb467a5beb1c666cf76a368978b5");
|
||||||
|
|
||||||
|
pub const INTEL_ROOT_EXPONENT: &[u8] =
|
||||||
|
&hex!("0000000000000000000000000000000000000000000000000000000000010001");
|
||||||
|
|
||||||
|
pub mod types;
|
||||||
|
|
||||||
|
pub mod verifier;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("Recovered digest from signature does not match the specified report")]
|
||||||
|
RecoveredDigestMismatch,
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::Binary;
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct IASReport {
|
||||||
|
pub report: ReportBody,
|
||||||
|
#[serde(rename = "reportsig")]
|
||||||
|
pub report_sig: Binary,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub struct ReportBody {
|
||||||
|
pub id: String,
|
||||||
|
pub timestamp: String,
|
||||||
|
pub version: u64,
|
||||||
|
#[serde(rename = "epidPseudonym")]
|
||||||
|
pub epid_pseudonym: Binary,
|
||||||
|
#[serde(rename = "advisoryURL")]
|
||||||
|
pub advisory_url: String,
|
||||||
|
#[serde(rename = "advisoryIDs")]
|
||||||
|
pub advisory_ids: Vec<String>,
|
||||||
|
#[serde(rename = "isvEnclaveQuoteStatus")]
|
||||||
|
pub isv_enclave_quote_status: String,
|
||||||
|
#[serde(rename = "platformInfoBlob")]
|
||||||
|
pub platform_info_blob: String,
|
||||||
|
#[serde(rename = "isvEnclaveQuoteBody")]
|
||||||
|
pub isv_enclave_quote_body: IsvEnclaveQuoteBody,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
#[serde(transparent)]
|
||||||
|
pub struct IsvEnclaveQuoteBody(Binary);
|
||||||
|
|
||||||
|
impl IsvEnclaveQuoteBody {
|
||||||
|
pub fn mrenclave(&self) -> [u8; 32] {
|
||||||
|
Self::array_chunk(self.0.as_slice(), 112)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn user_data(&self) -> [u8; 64] {
|
||||||
|
Self::array_chunk(self.0.as_slice(), 368)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn array_chunk<const N: usize>(quote_body: &[u8], offset: usize) -> [u8; N] {
|
||||||
|
assert!(offset + N <= quote_body.len());
|
||||||
|
quote_body[offset..offset + N]
|
||||||
|
.try_into()
|
||||||
|
.expect("array length mismatch")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,172 @@
|
||||||
|
use cosmwasm_std::ensure_eq;
|
||||||
|
use num_bigint::BigUint;
|
||||||
|
use sha2::{Digest, Sha256};
|
||||||
|
|
||||||
|
use crate::intel_sgx::epid::types::IASReport;
|
||||||
|
use crate::intel_sgx::epid::Error as EpidError;
|
||||||
|
use crate::intel_sgx::epid::{INTEL_ROOT_EXPONENT, INTEL_ROOT_MODULUS};
|
||||||
|
use crate::intel_sgx::Error;
|
||||||
|
|
||||||
|
/// Given an RSA signature and the signer's exponent + modulus we recover the digest that was signed by the signature.
|
||||||
|
pub fn recover_signature_digest(signature: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec<u8> {
|
||||||
|
let sig_as_bignum_be = BigUint::from_bytes_be(signature);
|
||||||
|
let intel_modulus_be = BigUint::from_bytes_be(modulus);
|
||||||
|
let intel_exponent_be = BigUint::from_bytes_be(exponent);
|
||||||
|
|
||||||
|
let digest_be = sig_as_bignum_be.modpow(&intel_exponent_be, &intel_modulus_be);
|
||||||
|
|
||||||
|
// last 32 bytes contain the digest
|
||||||
|
let digest_bytes = digest_be.to_bytes_be();
|
||||||
|
let n = digest_bytes.len();
|
||||||
|
digest_bytes[n - 32..n].to_vec()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify(
|
||||||
|
ias_report: IASReport,
|
||||||
|
mrenclave: impl AsRef<[u8]>,
|
||||||
|
user_data: impl AsRef<[u8]>,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
// Extract the payload from the quote body
|
||||||
|
let user_data_in_quote = ias_report.report.isv_enclave_quote_body.user_data();
|
||||||
|
|
||||||
|
// check user_report_data
|
||||||
|
ensure_eq!(
|
||||||
|
user_data_in_quote,
|
||||||
|
user_data.as_ref(),
|
||||||
|
Error::UserDataMismatch
|
||||||
|
);
|
||||||
|
|
||||||
|
// Extract the mrenclave from the quote body
|
||||||
|
let mrenclave_in_quote = ias_report.report.isv_enclave_quote_body.mrenclave();
|
||||||
|
|
||||||
|
// check mrenclave
|
||||||
|
ensure_eq!(
|
||||||
|
mrenclave_in_quote,
|
||||||
|
mrenclave.as_ref(),
|
||||||
|
Error::MrEnclaveMismatch
|
||||||
|
);
|
||||||
|
|
||||||
|
// Recover the RSA signature's digest
|
||||||
|
let recovered_digest = recover_signature_digest(
|
||||||
|
ias_report.report_sig.as_slice(),
|
||||||
|
INTEL_ROOT_EXPONENT,
|
||||||
|
INTEL_ROOT_MODULUS,
|
||||||
|
);
|
||||||
|
// Convert the recovered digest into a byte slice
|
||||||
|
let recovered_digest = recovered_digest.as_slice();
|
||||||
|
|
||||||
|
// Convert the ias report as a json string, removing all the backslashes to escape stuff
|
||||||
|
let ias_report_asjson = serde_json::to_string(&ias_report.report)
|
||||||
|
.expect("infallible serializer for IASReport")
|
||||||
|
.replace('\\', "");
|
||||||
|
// Convert the ias report without the back slashes to bytes
|
||||||
|
let ias_report_asbytes = ias_report_asjson.as_bytes();
|
||||||
|
// We are going to calculate our own digest of the ias report
|
||||||
|
let mut hasher = Sha256::default();
|
||||||
|
// Update the hasher contents with that of the ias report json
|
||||||
|
hasher.update(ias_report_asbytes);
|
||||||
|
// finalize the sha256 hasher so that it produces a byte slice of the digest, should be 32 bytes
|
||||||
|
let ias_report_digest = &hasher.finalize()[..];
|
||||||
|
|
||||||
|
// ensure that the recovered digest from the signature matches the digest of the report
|
||||||
|
ensure_eq!(
|
||||||
|
ias_report_digest,
|
||||||
|
recovered_digest,
|
||||||
|
EpidError::RecoveredDigestMismatch
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use cosmwasm_schema::cw_serde;
|
||||||
|
use cosmwasm_std::HexBinary;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[cw_serde]
|
||||||
|
pub enum QueryMsg {
|
||||||
|
/// Verify an attestation
|
||||||
|
VerifyEpidAttestation {
|
||||||
|
// The report that is generated by an enclave
|
||||||
|
report: IASReport,
|
||||||
|
// The MRENCLAVE of this enclave (as hex string)
|
||||||
|
mrenclave: HexBinary,
|
||||||
|
// User data - whose commitment is in the `user_report_data` (as hex string)
|
||||||
|
user_data: HexBinary,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_attestation(query_verifier: &str) -> (IASReport, HexBinary, HexBinary) {
|
||||||
|
let query_verifier: QueryMsg =
|
||||||
|
serde_json::from_str(query_verifier).expect("deserialize query");
|
||||||
|
match query_verifier {
|
||||||
|
QueryMsg::VerifyEpidAttestation {
|
||||||
|
report,
|
||||||
|
mrenclave,
|
||||||
|
user_data,
|
||||||
|
} => (report, mrenclave, user_data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_attestation(query_verifier: &str) {
|
||||||
|
let (report, mrenclave, user_data) = parse_attestation(query_verifier);
|
||||||
|
verify(report, mrenclave, user_data).expect("RA verification failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_verifier_ok() {
|
||||||
|
verify_attestation(
|
||||||
|
r#"{
|
||||||
|
"verify_epid_attestation": {
|
||||||
|
"report": {"report":{"id":"5246688123689513540899231107533660789","timestamp":"2024-02-07T17:06:23.913745","version":4,"epidPseudonym":"+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=","advisoryURL":"https://security-center.intel.com","advisoryIDs":["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"],"isvEnclaveQuoteStatus":"CONFIGURATION_AND_SW_HARDENING_NEEDED","platformInfoBlob":"150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1","isvEnclaveQuoteBody":"AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"reportsig":"YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="},
|
||||||
|
"mrenclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||||
|
"user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_verifier_bad_mrenclave() {
|
||||||
|
verify_attestation(
|
||||||
|
r#"{
|
||||||
|
"verify_epid_attestation": {
|
||||||
|
"report": {"report":{"id":"5246688123689513540899231107533660789","timestamp":"2024-02-07T17:06:23.913745","version":4,"epidPseudonym":"+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=","advisoryURL":"https://security-center.intel.com","advisoryIDs":["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"],"isvEnclaveQuoteStatus":"CONFIGURATION_AND_SW_HARDENING_NEEDED","platformInfoBlob":"150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1","isvEnclaveQuoteBody":"AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"reportsig":"YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="},
|
||||||
|
"mrenclave": "f3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||||
|
"user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_verifier_bad_user_data() {
|
||||||
|
verify_attestation(
|
||||||
|
r#"{
|
||||||
|
"verify_epid_attestation": {
|
||||||
|
"report": {"report":{"id":"5246688123689513540899231107533660789","timestamp":"2024-02-07T17:06:23.913745","version":4,"epidPseudonym":"+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=","advisoryURL":"https://security-center.intel.com","advisoryIDs":["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"],"isvEnclaveQuoteStatus":"CONFIGURATION_AND_SW_HARDENING_NEEDED","platformInfoBlob":"150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1","isvEnclaveQuoteBody":"AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"reportsig":"YcY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="},
|
||||||
|
"mrenclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||||
|
"user_data": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_verifier_bad_platform_info_blob() {
|
||||||
|
verify_attestation(
|
||||||
|
r#"{
|
||||||
|
"verify_epid_attestation": {
|
||||||
|
"report": {"report":{"id":"5246688123689513540899231107533660789","timestamp":"2024-02-07T17:06:23.913745","version":4,"epidPseudonym":"+CUyIi74LPqS6M0NF7YrSxLqPdX3MKs6D6LIPqRG/ZEB4WmxZVvxAJwdwg/0m9cYnUUQguLnJotthX645lAogfJgO8Xg5/91lSegwyUKvHmKgtjOHX/YTbVe/wmgWiBdaL+KmarY0Je459Px/FqGLWLsAF7egPAJRd1Xn88Znrs=","advisoryURL":"https://security-center.intel.com","advisoryIDs":["INTEL-SA-00161","INTEL-SA-00219","INTEL-SA-00289","INTEL-SA-00334","INTEL-SA-00615"],"isvEnclaveQuoteStatus":"CONFIGURATION_AND_SW_HARDENING_NEEDED","platformInfoBlob":"150200650000080000141402040180070000000000000000000D00000C000000020000000000000CB0F08115F3DE71AE97980FE5E10B042054930ACE356C79EC44603D3F890756EC6ED73927A7C58CDE9AF1E754AEC77E335E8D80294407936BEB6404F27669FF7BB1","isvEnclaveQuoteBody":"AgABALAMAAAPAA8AAAAAAFHK9aSLRQ1iSu/jKG0xSJQAAAAAAAAAAAAAAAAAAAAAFBQCBwGAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAHAAAAAAAAAOPC8qW4QNieBprK/8rbZRDvhmpz06nuVxAO1fhkbuS7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc8uUpEUEPvz8ZkFapjVh5WlWaLoAJM/f80T0EhGInHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACRE7C+d+1dDWhoDsdyBrjVh+1AZ5txMhzN1UBeTVSmggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"},"reportsig":"YaY4SPvkfR4P2E8A5huutCeS+vY/ir+xq6disalNfNtAcUyOIOqTPVXhAZgY1M5B47Hjj1oYWf2qC2w+dnj7VcZjzO9oR0pJYdA+A7jaVrNzH2eXA79yICkuU8WE/x58I0j5vjXLoHXahaKlpZkMeTphqBY8u+FTVSdP3cWPho4viPapTfQRuEWmYq4KIq2zSr6wLg3Pz+yQ+G3e9BASVkLYxdYGTDFH1pMmfas9SEI7V4I+j8DaXmL8bucSRakmcQdmDMPGiA7mvIhSAlprzCrdxM7CHeUC6MPLN1fmFFcc9kyO/ved69j/651MWC83GgxSJ15L80U+DQzmrSW8xg=="},
|
||||||
|
"mrenclave": "e3c2f2a5b840d89e069acaffcadb6510ef866a73d3a9ee57100ed5f8646ee4bb",
|
||||||
|
"user_data": "9113b0be77ed5d0d68680ec77206b8d587ed40679b71321ccdd5405e4d54a6820000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
22
bisenzone-cw-mvp/packages/quartz-tee-ra/src/lib.rs
Normal file
22
bisenzone-cw-mvp/packages/quartz-tee-ra/src/lib.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#![warn(
|
||||||
|
clippy::checked_conversions,
|
||||||
|
clippy::panic,
|
||||||
|
clippy::panic_in_result_fn,
|
||||||
|
clippy::unwrap_used,
|
||||||
|
rust_2018_idioms,
|
||||||
|
unused_lifetimes
|
||||||
|
)]
|
||||||
|
#![deny(
|
||||||
|
trivial_casts,
|
||||||
|
trivial_numeric_casts,
|
||||||
|
unused_import_braces,
|
||||||
|
unused_qualifications,
|
||||||
|
warnings
|
||||||
|
)]
|
||||||
|
#![forbid(unsafe_code)]
|
||||||
|
|
||||||
|
pub mod intel_sgx;
|
||||||
|
|
||||||
|
pub use intel_sgx::epid::types::IASReport;
|
||||||
|
pub use intel_sgx::epid::verifier::verify as verify_epid_attestation;
|
||||||
|
pub use intel_sgx::Error;
|
Loading…
Reference in a new issue