Skip to content

Commit

Permalink
Merge pull request #38 from mkulke/mkulke/az-tdx-vtpm
Browse files Browse the repository at this point in the history
Add experimental TDX attester/verifier crate (#35)
  • Loading branch information
iaguis authored Oct 23, 2023
2 parents 20fd006 + 88775fc commit 39bea67
Show file tree
Hide file tree
Showing 35 changed files with 481 additions and 25 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: e2e

on:
pull_request:
push:
branches: [ "main" ]

jobs:
Expand Down
14 changes: 5 additions & 9 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ env:

jobs:
build:

runs-on: ubuntu-latest
defaults:
run:
working-directory: az-cvm-vtpm

steps:
- uses: actions/checkout@v3

- name: Install deps
run: sudo apt-get update && sudo apt-get install -y libtss2-dev

- uses: actions/checkout@v3

- uses: actions-rs/toolchain@v1
with:
profile: minimal
Expand All @@ -34,24 +36,18 @@ jobs:
- name: Build
run: cargo build --verbose --all
working-directory: az-snp-vtpm

- name: Check verifier-only
run: cargo check --verbose --no-default-features --features=verifier
working-directory: az-snp-vtpm

- name: Check attester-only
run: cargo check --verbose --no-default-features --features=attester
working-directory: az-snp-vtpm

- name: Run tests
run: cargo test --verbose --all
working-directory: az-snp-vtpm

- name: Format
run: cargo fmt --all -- --check
working-directory: az-snp-vtpm

- name: Lint
run: cargo clippy --all-targets --all-features --all -- -D warnings
working-directory: az-snp-vtpm
4 changes: 2 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

Assorted tools and libraries to use with [Azure CVMs](https://azure.microsoft.com/en-us/solutions/confidential-compute/).

# vTPM-SNP
## az-cvm-vtpm

Library and CLI to integrate with vTPM on SEV-SNP enabled machines.
Attestation for Azure Confidential Virtual Machines
1 change: 1 addition & 0 deletions az-snp-vtpm/.gitignore → az-cvm-vtpm/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
target
arm/*.json
Cargo.lock
*.swp
7 changes: 7 additions & 0 deletions az-cvm-vtpm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[workspace]
members = [
"az-snp-vtpm",
"az-tdx-vtpm",
"az-snp-vtpm/example",
]
resolver = "2"
11 changes: 11 additions & 0 deletions az-cvm-vtpm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# az-cvm-vtpm

Attestation for Azure Confidential Virtual Machines

## az-snp-vtpm

Attestation Library for Azure AMD SEV-SNP Confidential Virtual Machines.

## az-tdx-vtpm

Attestation Library for Azure Intel TDX Confidential Virtual Machines (Limited Preview).
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,10 @@ sev = "1.2.0"
sha2 = "0.10.6"
static_assertions = "^1.1.0"
thiserror = "1.0.38"
tss-esapi = "7.2"
tss-esapi = "7.4"
ureq = { version = "2.6.2", default-features = false, features = ["json"] }

[features]
default = ["attester", "verifier"]
attester = []
verifier = ["openssl", "sev/openssl", "ureq/tls"]

[workspace]
members = ["example"]
File renamed without changes.
14 changes: 6 additions & 8 deletions az-snp-vtpm/README.md → az-cvm-vtpm/az-snp-vtpm/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# az-snp-vtpm

[![Rust](https://github.com/kinvolk/azure-cvm-tooling/actions/workflows/rust.yml/badge.svg)](https://github.com/kinvolk/azure-cvm-tooling/actions/workflows/rust.yml)
[![Crate](https://img.shields.io/crates/v/az-snp-vtpm.svg)](https://crates.io/crates/az-snp-vtpm)
[![Docs](https://docs.rs/rand/badge.svg)](https://docs.rs/az-snp-vtpm)

**vTPM based SEV-SNP attestation for Azure Confidential VMs**
# az-snp-vtpm

This library enables guest attestation flows for [SEV-SNP CVMs on Azure](https://learn.microsoft.com/en-us/azure/confidential-computing/confidential-vm-overview). Please refer to the documentation in [this repository](https://github.com/Azure/confidential-computing-cvm-guest-attestation) for details on the attestation procedure.

Expand All @@ -20,8 +18,8 @@ make deploy
## Build & Install

```bash
cargo b --release
scp target/release/snp-vtpm azureuser@$CONFIDENTIAL_VM:
cargo b --release -p az-snp-vtpm
scp ../target/release/snp-vtpm azureuser@$CONFIDENTIAL_VM:
```

## Run Binary
Expand All @@ -37,7 +35,7 @@ sudo ./snp-vtpm -p
There is a project in the `./example` folder depicting how the crate can be leveraged in a Remote Attestation flow. **Note:** the code is merely illustrative and doesn't feature exhaustive validation, which would be required in a production scenario.

```bash
cargo b -p example
cargo b -p snp-example
```

## SEV-SNP Report & vTPM
Expand All @@ -56,12 +54,12 @@ The vTPM is linked to the SEV-SNP report via the vTPM Attestation Key (AK). The
│ └──────────────────────┘ │ │ └────────────────────┘ │ │ │
│ ┌──────────────┐ │ └──────────────────────┬─┘ ─┘ │
│ │ vTPM Quote │ │ ┌────────────────────┐ │ │
│ │ │ │ │ HCL Report │ │ │
│ │ │ │ │ HCL Report │ │ │
signs ┌─ ┌─┴────────────┐ │ │ │ │ │ sha256
│ │ │ Message │ │ │ │ ┌────────────────┐ │ │ │
│ │ │ │ │ │ │ │ SEV-SNP Report │ │ │ │
│ │ │ ┌──────────┐ │ │ │ │ │ │ │ │ │
│ │ │ │ PCR0 │ │ │ │ │ │ ┌──────────────┴─┴─┴─┐ │
│ │ │ │ PCR0 │ │ │ │ │ │ ┌──────────────┴─┴─┴─┐ │
│ │ │ └──────────┘ │ │ │ │ │ │ Report Data │ ◄───┘
│ │ │ ... │ │ │ │ │ └──────────────┬─┬─┬─┘
│ │ │ ┌──────────┐ │ │ │ │ └────────────────┘ │ │
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "example"
name = "snp-example"
version = "0.1.0"
edition = "2021"

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
35 changes: 35 additions & 0 deletions az-cvm-vtpm/az-tdx-vtpm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[package]
name = "az-tdx-vtpm"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[lib]
path = "src/lib.rs"

[[bin]]
name = "tdx-vtpm"
path = "src/main.rs"

[dependencies]
anyhow = "1.0.75"
base64-url = "2.0.0"
bincode = "1.3.3"
jsonwebkey = { version = "0.3.5", features = ["pkcs-convert"] }
memoffset = "0.9.0"
serde = { version = "1.0.189", features = ["derive"] }
serde-big-array = "0.5.1"
serde_json = "1.0.107"
sha2 = "0.10.8"
tss-esapi = "7.4"
ureq = { version = "2.6.2", default-features = false, features = ["json"] }
az-snp-vtpm = { path = "../az-snp-vtpm" }
sev = "1.2.0"
thiserror = "1.0.49"
openssl = { version = "0.10", optional = true }

[features]
default = ["attester", "verifier"]
attester = []
verifier = ["az-snp-vtpm/verifier", "openssl"]
21 changes: 21 additions & 0 deletions az-cvm-vtpm/az-tdx-vtpm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# az-tdx-vtpm

[![Rust](https://github.com/kinvolk/azure-cvm-tooling/actions/workflows/rust.yml/badge.svg)](https://github.com/kinvolk/azure-cvm-tooling/actions/workflows/rust.yml)

> [!WARNING]
> This library enables guest attestation and verification for [TDX CVMs on Azure](https://learn.microsoft.com/en-us/azure/confidential-computing/tdx-confidential-vm-overview). TDX CVMs are currently in limited preview and hence the library is considered experimental and subject to change.
## Build & Install

```bash
cargo b --release -p az-tdx-vtpm
scp ../target/release/tdx-vtpm azureuser@$CONFIDENTIAL_VM:
```

## Run Binary

On the TDX CVM, retrieve a TD Quote and write it to disk:

```bash
sudo ./tdx-vtpm
```
169 changes: 169 additions & 0 deletions az-cvm-vtpm/az-tdx-vtpm/src/hcl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use crate::tdx::TdxVmReport;
use jsonwebkey::JsonWebKey;
use memoffset::offset_of;
use serde::{Deserialize, Serialize};
use serde_big_array::BigArray;
use sev::firmware::guest::AttestationReport as SnpVmReport;
use sha2::{Digest, Sha256};
use std::mem;
use thiserror::Error;

const HCL_AKPUB_KEY_ID: &str = "HCLAkPub";
const MAX_REPORT_SIZE: usize = mem::size_of::<SnpVmReport>();
const MIN_REPORT_SIZE: usize = mem::size_of::<TdxVmReport>();
const SNP_REPORT_TYPE: u32 = 2;
const TDX_REPORT_TYPE: u32 = 4;

#[derive(Error, Debug)]
pub enum HclError {
#[error("invalid report type")]
InvalidReportType,
#[error("AkPub not found")]
AkPubNotFound,
#[error("binary parse error")]
BinaryParseError(#[from] bincode::Error),
#[error("JSON parse error")]
JsonParseError(#[from] serde_json::Error),
}

#[derive(Deserialize, Debug)]
struct VarDataKeys {
keys: Vec<JsonWebKey>,
}

#[repr(u32)]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
enum IgvmHashType {
Invalid = 0,
Sha256,
Sha384,
Sha512,
}

#[repr(C)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct IgvmRequestData {
data_size: u32,
version: u32,
report_type: u32,
report_data_hash_type: IgvmHashType,
variable_data_size: u32,
variable_data: [u8; 0],
}

#[repr(C)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct AttestationHeader {
signature: u32,
version: u32,
report_size: u32,
request_type: u32,
status: u32,
reserved: [u32; 3],
}

#[repr(C)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct HwReport {
tdx_vm_report: TdxVmReport,
#[serde(with = "BigArray")]
_padding: [u8; MAX_REPORT_SIZE - MIN_REPORT_SIZE],
}

#[repr(C)]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
struct AttestationReport {
header: AttestationHeader,
hw_report: HwReport,
hcl_data: IgvmRequestData,
}

pub struct HclReport {
bytes: Vec<u8>,
attestation_report: AttestationReport,
report_type: ReportType,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ReportType {
Tdx,
Snp,
}

impl HclReport {
pub fn new(bytes: Vec<u8>) -> Result<Self, HclError> {
let attestation_report: AttestationReport = bincode::deserialize(&bytes)?;
let report_type = match attestation_report.hcl_data.report_type {
TDX_REPORT_TYPE => ReportType::Tdx,
SNP_REPORT_TYPE => ReportType::Snp,
_ => return Err(HclError::InvalidReportType),
};

let report = Self {
bytes,
attestation_report,
report_type,
};
Ok(report)
}

pub fn report_type(&self) -> ReportType {
self.report_type
}

pub fn tdx_report_slice(&self) -> &[u8] {
let tdx_report_offset = offset_of!(AttestationReport, hw_report);
let tdx_report_end = tdx_report_offset + mem::size_of::<TdxVmReport>();
&self.bytes[tdx_report_offset..tdx_report_end]
}

pub fn var_data_sha256(&self) -> [u8; 32] {
if self.attestation_report.hcl_data.report_data_hash_type != IgvmHashType::Sha256 {
unimplemented!(
"Only SHA256 is supported, got {:?}",
self.attestation_report.hcl_data.report_data_hash_type
);
}
let mut hasher = Sha256::new();
hasher.update(self.var_data_slice());
let hash = hasher.finalize();
hash.into()
}

fn var_data_slice(&self) -> &[u8] {
let var_data_offset =
offset_of!(AttestationReport, hcl_data) + offset_of!(IgvmRequestData, variable_data);
let hcl_data = &self.attestation_report.hcl_data;
let var_data_end = var_data_offset + hcl_data.variable_data_size as usize;
&self.bytes[var_data_offset..var_data_end]
}

pub fn ak_pub(&self) -> Result<JsonWebKey, HclError> {
let VarDataKeys { keys } = serde_json::from_slice(self.var_data_slice())?;
let ak_pub = keys
.into_iter()
.find(|key| {
let Some(ref key_id) = key.key_id else {
return false;
};
key_id == HCL_AKPUB_KEY_ID
})
.ok_or(HclError::AkPubNotFound)?;
Ok(ak_pub)
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn parse_hcl_report() {
let bytes: &[u8] = include_bytes!("../test/hcl_report.bin");
let hcl_report = HclReport::new(bytes.to_vec()).unwrap();
let _ = hcl_report.ak_pub().unwrap();
}
}
Loading

0 comments on commit 39bea67

Please sign in to comment.