Skip to content

Commit

Permalink
Add cli to decode quote
Browse files Browse the repository at this point in the history
  • Loading branch information
kvinwang committed Oct 30, 2024
1 parent 006d887 commit 85cfda0
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 8 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Cargo.lock
/target
target/
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,4 @@ std = [
]
report = ["std", "tracing", "futures"]
js = ["ring/wasm32_unknown_unknown_js", "getrandom", "serde-wasm-bindgen", "wasm-bindgen"]
hex-bytes = []
15 changes: 15 additions & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "dcap-qvl-cli"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "dcap-qvl"
path = "src/main.rs"

[dependencies]
anyhow = "1.0.91"
clap = { version = "4.5.20", features = ["derive"] }
dcap-qvl = { path = "../", features = ["hex-bytes"] }
hex = "0.4.3"
serde_json = "1.0.132"
11 changes: 11 additions & 0 deletions cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# dcap-qvl-cli

A CLI tool to decode TDX/SGX quote files.

## Usage

```
git clone https://github.com/Phala-Network/dcap-qvl.git
cd dcap-qvl/cli
cargo run -- decode-quote --hex ../sample/tdx-quote.hex | jq .
```
55 changes: 55 additions & 0 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//! CLI for dcap-qvl
//! Usage:
//! dcap-qvl decode-quote [--hex] <quote_file>
//! dcap-qvl verify-quote <quote_file> <collateral_file>

use std::path::PathBuf;

use anyhow::{Context as _, Result};
use clap::{Args, Parser, Subcommand};
use dcap_qvl::quote::Quote;

#[derive(Parser)]
struct Cli {
#[command(subcommand)]
command: Commands,
}

#[derive(Subcommand)]
enum Commands {
/// Decode a quote file
DecodeQuote(DecodeQuoteArgs),
}

#[derive(Args)]
struct DecodeQuoteArgs {
#[arg(long)]
hex: bool,
quote_file: PathBuf,
}

fn decode_quote(args: DecodeQuoteArgs) -> Result<Quote> {
let quote = std::fs::read(args.quote_file).context("Failed to read quote file")?;
let quote = if args.hex {
let quote = quote.strip_prefix(b"0x").unwrap_or(&quote);
hex::decode(quote).context("Failed to decode quote file")?
} else {
quote
};
let quote = Quote::parse(&quote).context("Failed to parse quote")?;
Ok(quote)
}

fn command_decode_quote(args: DecodeQuoteArgs) -> Result<()> {
let quote = decode_quote(args).context("Failed to decode quote")?;
let json = serde_json::to_string(&quote).context("Failed to serialize quote")?;
println!("{}", json);
Ok(())
}

fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::DecodeQuote(args) => command_decode_quote(args).context("Failed to decode quote"),
}
}
1 change: 1 addition & 0 deletions sample/tdx-quote.hex
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0x040002008100000000000000939a7233f79c4ca9940a0db3957f060783fbfe61525f55581315cd9dc950f44700000000050102000000000000000000000000001cc6a17ab799e9a693fac7536be61c12ee1e0fabada82d0c999e08ccee2aa86de77b0870f558c570e7ffe55d6d47fa0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000e7020600000000007ba9e262ce6979087e34632603f354dd8f8a870f5947d116af8114db6c9d0d74c48bec4280e5b4f4a37025a10905bb290000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004574c098915caf3e82057817dbd135c1ed0ee1b39ac300c921479e2f5ebf5726a13ee0c8745ac891b6aee7c4f9664610000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000547fcba4630bfb981169a8a1903b79c244933413409dd0387acbd8e3b985bcc9164cf52735cd31f60bf2c5d1220c113f7148f47ef58b475fce69b386e2d6b4c964a9533cc328ea8e544db66612a5174698d006951cefa8fd4450e884300638e567e22f9a012ef5754aa6a9d9564fcd8acc100000cdef13e9c54d734e810d8fc23df4a68ae65bf687754b021710cb25b7354f4a3ee34aa7e5b2aab30d0e85193c8c68b71118c0ac5e14e1d0368d41046609f38c024996a9e56e40ac6c0b019709537f16d751c03e8c0d905d79f224ff06ddc4102860a8770107748c011cdbfcccc857e418735b699ac89dc2ed4da11d5125cb925e0600461000000202191b03ff0006000000000000000000000000000000000000000000000000000000000000000000000000000000001500000000000000e700000000000000e5a3a7b5d830c2953b98534c6c59a3a34fdc34e933f7f5898f0a85cf08846bca0000000000000000000000000000000000000000000000000000000000000000dc9e2a7c6f948f17474e34a7fc43ed030f7c1563f1babddf6340c82e0e54a8c500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000503bbfe5befa55a13e21747c3859f0b618a050312a0340e980187eea232356d60000000000000000000000000000000000000000000000000000000000000000791fc77d0260080a376494a35aa3a3dc64ff532d7642ec07e3bfd2da320f9180f2d4b27ecf6c2057f25326d7c0cf43d73504a3f9dbc7de8855bffb65ec52bf742000000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f05005e0e00002d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d49494538444343424a65674177494241674956414c5235544954392b396e73423142545a3173725851346c627752424d416f4743437147534d343942414d430a4d484178496a416742674e5642414d4d47556c756447567349464e4857434251513073675547786864475a76636d306751304578476a415942674e5642416f4d0a45556c756447567349454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155450a4341774351304578437a414a42674e5642415954416c56544d423458445449304d4467774d6a45784d54557a4e316f5844544d784d4467774d6a45784d54557a0a4e316f77634445694d434147413155454177775a535735305a5777675530645949464244537942445a584a3061575a70593246305a5445614d426747413155450a43677752535735305a577767513239796347397959585270623234784644415342674e564241634d43314e68626e526849454e7359584a684d517377435159440a5651514944414a445154454c4d416b474131554542684d4356564d775754415442676371686b6a4f5051494242676771686b6a4f50514d4242774e43414154590a77777155344778504a6a596f6a4d4752686136327970346a425164355744764b776d54366c6c314147786a59363870694a50676950686462387a544766374b620a314f79643153464f4d5a70594c795054427a59646f3449444444434341776777487759445652306a42426777466f41556c5739647a62306234656c4153636e550a3944504f4156634c336c5177617759445652306642475177596a42676f46366758495a616148523063484d364c79396863476b7564484a316333526c5a484e6c0a636e5a705932567a4c6d6c75644756734c6d4e766253397a5a3367765932567964476c6d61574e6864476c76626939324e4339775932746a636d772f593245390a6347786864475a76636d306d5a57356a62325270626d63395a4756794d423047413155644467515742425146303476507654474b7762416c356f54765664664d0a2b356a6e7554414f42674e56485138424166384542414d434273417744415944565230544151482f4241497741444343416a6b4743537147534962345451454e0a4151534341696f776767496d4d42344743697147534962345451454e41514545454e3564416f7135634b356e383277396f793165346e34776767466a42676f710a686b69472b453042445145434d494942557a415142677371686b69472b4530424451454341514942416a415142677371686b69472b45304244514543416749420a416a415142677371686b69472b4530424451454341774942416a415142677371686b69472b4530424451454342414942416a415142677371686b69472b4530420a4451454342514942417a415142677371686b69472b45304244514543426749424154415142677371686b69472b453042445145434277494241444151426773710a686b69472b4530424451454343414942417a415142677371686b69472b45304244514543435149424144415142677371686b69472b45304244514543436749420a4144415142677371686b69472b45304244514543437749424144415142677371686b69472b45304244514543444149424144415142677371686b69472b4530420a44514543445149424144415142677371686b69472b45304244514543446749424144415142677371686b69472b453042445145434477494241444151426773710a686b69472b45304244514543454149424144415142677371686b69472b4530424451454345514942437a416642677371686b69472b45304244514543456751510a4167494341674d4241414d4141414141414141414144415142676f71686b69472b45304244514544424149414144415542676f71686b69472b453042445145450a4241617777473841414141774477594b4b6f5a496876684e4151304242516f424154416542676f71686b69472b453042445145474242424a316472685349736d0a682b2f46793074746a6a762f4d45514743697147534962345451454e415163774e6a415142677371686b69472b45304244514548415145422f7a4151426773710a686b69472b45304244514548416745422f7a415142677371686b69472b45304244514548417745422f7a414b42676771686b6a4f5051514441674e48414442450a41694270455738754f726b537469486b4c4b6e6a426855416f637a39545733366a4e2f303765416844503635617749674d2f31474c58745a70446436706150760a535a386d4e7472543830305635346b465944474f7a4f78504374383d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436c6a4343416a32674177494241674956414a567658633239472b487051456e4a3150517a7a674658433935554d416f4743437147534d343942414d430a4d476778476a415942674e5642414d4d45556c756447567349464e48574342536232393049454e424d526f77474159445651514b4442464a626e526c624342440a62334a7762334a6864476c76626a45554d424947413155454277774c553246756447456751327868636d4578437a414a42674e564241674d416b4e424d5173770a435159445651514745774a56557a4165467730784f4441314d6a45784d4455774d5442614677307a4d7a41314d6a45784d4455774d5442614d484178496a41670a42674e5642414d4d47556c756447567349464e4857434251513073675547786864475a76636d306751304578476a415942674e5642416f4d45556c75644756730a49454e76636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b474131554543417743513045780a437a414a42674e5642415954416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a304441516344516741454e53422f377432316c58534f0a3243757a7078773734654a423732457944476757357258437478327456544c7136684b6b367a2b5569525a436e71523770734f766771466553786c6d546c4a6c0a65546d693257597a33714f42757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f536347724442530a42674e5648523845537a424a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b633256790a646d6c6a5a584d75615735305a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e5648513445466751556c5739640a7a62306234656c4153636e553944504f4156634c336c517744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159420a4166384341514177436759494b6f5a497a6a30454177494452774177524149675873566b6930772b6936565947573355462f32327561586530594a446a3155650a6e412b546a44316169356343494359623153416d4435786b66545670766f34556f79695359787244574c6d5552344349394e4b7966504e2b0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949436a7a4343416a53674177494241674955496d554d316c71644e496e7a6737535655723951477a6b6e42717777436759494b6f5a497a6a3045417749770a614445614d4267474131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e760a636e4276636d4630615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a0a42674e5642415954416c56544d423458445445344d4455794d5445774e4455784d466f58445451354d54497a4d54497a4e546b314f566f77614445614d4267470a4131554541777752535735305a5777675530645949464a766233516751304578476a415942674e5642416f4d45556c756447567349454e76636e4276636d46300a615739754d5251774567594456515148444174545957353059534244624746795954454c4d416b47413155454341774351304578437a414a42674e56424159540a416c56544d466b77457759484b6f5a497a6a3043415159494b6f5a497a6a3044415163445167414543366e45774d4449595a4f6a2f69505773437a61454b69370a314f694f534c52466857476a626e42564a66566e6b59347533496a6b4459594c304d784f346d717379596a6c42616c54565978465032734a424b357a6c4b4f420a757a43427544416642674e5648534d4547444157674251695a517a575770303069664f44744a5653763141624f5363477244425342674e5648523845537a424a0a4d45656752614244686b466f64485277637a6f764c324e6c636e52705a6d6c6a5958526c63793530636e567a6447566b63325679646d6c6a5a584d75615735300a5a577775593239744c306c756447567355306459556d397664454e424c6d526c636a416442674e564851344546675155496d554d316c71644e496e7a673753560a55723951477a6b6e4271777744675944565230504151482f42415144416745474d42494741315564457745422f7751494d4159424166384341514577436759490a4b6f5a497a6a3045417749445351417752674968414f572f35516b522b533943695344634e6f6f774c7550524c735747662f59693747535839344267775477670a41694541344a306c72486f4d732b586f356f2f7358364f39515778485241765a55474f6452513763767152586171493d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
77 changes: 70 additions & 7 deletions src/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,65 @@ use serde::{Deserialize, Serialize};

use crate::{constants::*, utils, Error};

#[cfg(feature = "hex-bytes")]
mod serde_bytes {
use serde::Deserialize;

pub(crate) trait FromBytes {
fn from_bytes(bytes: Vec<u8>) -> Option<Self>
where
Self: Sized;
}
impl FromBytes for Vec<u8> {
fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
Some(bytes)
}
}
impl<const N: usize> FromBytes for [u8; N] {
fn from_bytes(bytes: Vec<u8>) -> Option<Self> {
bytes.try_into().ok()
}
}

pub(crate) fn serialize<S: serde::Serializer>(
data: impl AsRef<[u8]>,
serializer: S,
) -> Result<S::Ok, S::Error> {
let hex_str = hex::encode(data);
serializer.serialize_str(&hex_str)
}

pub(crate) fn deserialize<'de, D: serde::Deserializer<'de>, T: FromBytes>(
deserializer: D,
) -> Result<T, D::Error> {
let hex_str = String::deserialize(deserializer)?;
let bytes = hex::decode(hex_str).map_err(serde::de::Error::custom)?;
T::from_bytes(bytes).ok_or_else(|| serde::de::Error::custom("invalid bytes"))
}
}

#[derive(Debug, Clone)]
pub struct Data<T> {
pub data: Vec<u8>,
_marker: core::marker::PhantomData<T>,
}

impl<T> Serialize for Data<T> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serde_bytes::serialize(&self.data, serializer)
}
}

impl<'de, T> Deserialize<'de> for Data<T> {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let data = serde_bytes::deserialize(deserializer)?;
Ok(Data {
data,
_marker: core::marker::PhantomData,
})
}
}

impl<T: Decode + Into<u64>> Decode for Data<T> {
fn decode<I: Input>(input: &mut I) -> Result<Self, scale::Error> {
let len = T::decode(input)?;
Expand All @@ -25,14 +78,16 @@ impl<T: Decode + Into<u64>> Decode for Data<T> {
}
}

#[derive(Decode, Debug)]
#[derive(Decode, Debug, Serialize, Deserialize)]
pub struct Header {
pub version: u16,
pub attestation_key_type: u16,
pub tee_type: u32,
pub qe_svn: u16,
pub pce_svn: u16,
#[serde(with = "serde_bytes")]
pub qe_vendor_id: [u8; 16],
#[serde(with = "serde_bytes")]
pub user_data: [u8; 20],
}

Expand Down Expand Up @@ -110,7 +165,7 @@ pub struct TDReport15 {
pub mr_service_td: [u8; 48],
}

#[derive(Decode)]
#[derive(Decode, Serialize, Deserialize)]
pub struct CertificationData {
pub cert_type: u16,
pub body: Data<u32>,
Expand All @@ -126,27 +181,35 @@ impl core::fmt::Debug for CertificationData {
}
}

#[derive(Decode, Debug)]
#[derive(Decode, Debug, Serialize, Deserialize)]
pub struct QEReportCertificationData {
#[serde(with = "serde_bytes")]
pub qe_report: [u8; ENCLAVE_REPORT_BYTE_LEN],
#[serde(with = "serde_bytes")]
pub qe_report_signature: [u8; QE_REPORT_SIG_BYTE_LEN],
pub qe_auth_data: Data<u16>,
pub certification_data: CertificationData,
}

#[derive(Decode, Debug)]
#[derive(Decode, Debug, Serialize, Deserialize)]
pub struct AuthDataV3 {
#[serde(with = "serde_bytes")]
pub ecdsa_signature: [u8; ECDSA_SIGNATURE_BYTE_LEN],
#[serde(with = "serde_bytes")]
pub ecdsa_attestation_key: [u8; ECDSA_PUBKEY_BYTE_LEN],
#[serde(with = "serde_bytes")]
pub qe_report: [u8; ENCLAVE_REPORT_BYTE_LEN],
#[serde(with = "serde_bytes")]
pub qe_report_signature: [u8; QE_REPORT_SIG_BYTE_LEN],
pub qe_auth_data: Data<u16>,
pub certification_data: CertificationData,
}

#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct AuthDataV4 {
#[serde(with = "serde_bytes")]
pub ecdsa_signature: [u8; ECDSA_SIGNATURE_BYTE_LEN],
#[serde(with = "serde_bytes")]
pub ecdsa_attestation_key: [u8; ECDSA_PUBKEY_BYTE_LEN],
pub certification_data: CertificationData,
pub qe_report_data: QEReportCertificationData,
Expand Down Expand Up @@ -181,7 +244,7 @@ impl Decode for AuthDataV4 {
}
}

#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub enum AuthData {
V3(AuthDataV3),
V4(AuthDataV4),
Expand Down Expand Up @@ -217,7 +280,7 @@ pub enum Report {
TD15(TDReport15),
}

#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct Quote {
pub header: Header,
pub report: Report,
Expand Down

0 comments on commit 85cfda0

Please sign in to comment.