Skip to content

Commit

Permalink
Add get_collateral_from_pcs
Browse files Browse the repository at this point in the history
  • Loading branch information
kvinwang committed Nov 7, 2024
1 parent 2b5103d commit a40b951
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 16 deletions.
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ Add the following dependency to your `Cargo.toml` file to use this crate:
dcap-qvl = "0.1.0"
```

# Example: Get Collateral from PCCS_URL and Verify Quote
# Examples

## Get Collateral from PCCS_URL and Verify Quote

To get collateral from a PCCS_URL and verify a quote, you can use the following example code:
```rust
Expand All @@ -36,6 +38,22 @@ async fn main() {
}
```

## Get Collateral from Intel PCS and Verify Quote

```rust
use dcap_qvl::collateral::get_collateral_from_pcs;
use dcap_qvl::verify::verify;

#[tokio::main]
async fn main() {
let quote = std::fs::read("tdx_quote").expect("tdx_quote is not found");
let collateral = get_collateral_from_pcs(&quote, std::time::Duration::from_secs(10)).await.expect("failed to get collateral");
let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs();
let tcb = verify(&quote, &collateral, now).expect("failed to verify quote");
println!("{:?}", tcb);
}
```

<!-- cargo-rdme end -->

# License
Expand Down
1 change: 1 addition & 0 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ clap = { version = "4.5.20", features = ["derive"] }
dcap-qvl = { path = "../", features = ["hex-bytes"] }
hex = "0.4.3"
serde_json = "1.0.132"
tokio = { version = "1.41.0", features = ["full"] }
59 changes: 45 additions & 14 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use std::path::PathBuf;

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

#[derive(Parser)]
struct Cli {
Expand All @@ -17,7 +19,9 @@ struct Cli {
#[derive(Subcommand)]
enum Commands {
/// Decode a quote file
DecodeQuote(DecodeQuoteArgs),
Decode(DecodeQuoteArgs),
/// Verify a quote file
Verify(VerifyQuoteArgs),
}

#[derive(Args)]
Expand All @@ -29,28 +33,55 @@ struct DecodeQuoteArgs {
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")?
#[derive(Args)]
struct VerifyQuoteArgs {
/// Indicate the quote file is in hex format
#[arg(long)]
hex: bool,
/// The quote file
quote_file: PathBuf,
}

fn hex_decode(input: &[u8], is_hex: bool) -> Result<Vec<u8>> {
if is_hex {
let input = input.strip_prefix(b"0x").unwrap_or(input);
hex::decode(input).context("Failed to decode quote file")
} else {
quote
};
let quote = Quote::parse(&quote).context("Failed to parse quote")?;
Ok(quote)
Ok(input.to_vec())
}
}

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")?;
let quote = std::fs::read(args.quote_file).context("Failed to read quote file")?;
let quote = hex_decode(&quote, args.hex)?;
let decoded_quote = Quote::parse(&quote).context("Failed to parse quote")?;
let json = serde_json::to_string(&decoded_quote).context("Failed to serialize quote")?;
println!("{}", json);
Ok(())
}

fn main() -> Result<()> {
async fn command_verify_quote(args: VerifyQuoteArgs) -> Result<()> {
let quote = std::fs::read(args.quote_file).context("Failed to read quote file")?;
let quote = hex_decode(&quote, args.hex)?;
println!("Getting collateral...");
let collateral = get_collateral_from_pcs(&quote, std::time::Duration::from_secs(60)).await?;
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)?
.as_secs();
verify(&quote, &collateral, now)
.ok()
.context("Failed to verify quote")?;
eprintln!("Quote verified");
Ok(())
}

#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
match cli.command {
Commands::DecodeQuote(args) => command_decode_quote(args).context("Failed to decode quote"),
Commands::Decode(args) => command_decode_quote(args).context("Failed to decode quote"),
Commands::Verify(args) => command_verify_quote(args)
.await
.context("Failed to verify quote"),
}
}
17 changes: 16 additions & 1 deletion src/collateral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ pub async fn get_collateral(
.get(format!("{base_url}/pckcrl?ca=processor"))
.send()
.await?;
println!("{:#?}", response);
pck_crl_issuer_chain = get_header(&response, "SGX-PCK-CRL-Issuer-Chain")?;
pck_crl = response.text().await?;
};
Expand Down Expand Up @@ -116,3 +115,19 @@ pub async fn get_collateral(
qe_identity_signature,
})
}

/// Get collateral given DCAP quote from Intel PCS.
///
/// # Arguments
///
/// * `quote` - The raw quote to verify. Supported SGX and TDX quotes.
/// * `timeout` - The timeout for the request. (e.g. `Duration::from_secs(10)`)
///
/// # Returns
///
/// * `Ok(QuoteCollateralV3)` - The quote collateral
/// * `Err(Error)` - The error
pub async fn get_collateral_from_pcs(quote: &[u8], timeout: Duration) -> Result<QuoteCollateralV3> {
const PCS_URL: &str = "https://api.trustedservices.intel.com/sgx/certification/v4";
get_collateral(PCS_URL, quote, timeout).await
}
6 changes: 6 additions & 0 deletions src/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,12 @@ pub enum Report {
TD15(TDReport15),
}

impl Report {
pub fn is_sgx(&self) -> bool {
matches!(self, Report::SgxEnclave(_))
}
}

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

0 comments on commit a40b951

Please sign in to comment.