AMD SEV-SNP rust utils and primitives.
Instead of cargo test
, run:
shell
make test
| Variable | Default | Description | |----------------------------|--------------------|-----------------------------------------------| | SEVSNPCACHEPATH | /var/cache/sev-snp | Path to store downloaded certs. | | SEVSNPCACHEENTRIES_VCEK | 100 | Max cache entries for VCEK certs (in-memory). |
To request a report from a SEV-SNP capable CPU (the same functionality as sev-guest-get-report
):
```rust use sevsnputils::{AttestationReport, Requester};
fn main() { let report = AttestationReport::request() .expect("failed to request guest report");
println!("version: {:?}", report.version);
// Or raw bytes
let report_bytes = AttestationReport::request_raw()
.expect("failed to request guest report");
println!("bytes len: {:?}", report_bytes.len());
} ```
Parse a guest_report.bin file from sev-guest-get-report
(or one saved from AttestationReport::request_raw()
):
```rust use sevsnputils::AttestationReport;
fn main() { let report = AttestationReport::fromfile("./guestreport.bin") .expect("failed to parse guest report");
println!("version: {:?}", report.version);
println!("guest_svn: {:?}", report.guest_svn);
println!("policy: {:?}", report.policy);
println!("platform_version: {:?}", report.platform_version.raw_decimal());
println!("measurement: {}", report.measurement_hex());
println!("report data: {}", report.report_data_hex());
println!("id key digest: {}", report.id_key_digest_hex());
println!("author key digest: {}", report.author_key_digest_hex());
println!("chip id: {}", report.chip_id_hex());
println!("hash: {}", report.sha384_hex());
println!("signature:");
println!(" r: {}", report.signature.r_hex());
println!(" s: {}", report.signature.s_hex());
} ```
The verification process:
Verify a guest_report.bin file:
```rust use sevsnputils::{AttestationReport, Verification, Policy};
async fn verifyguest() { let report = AttestationReport::fromfile("./guest_report.bin") .expect("failed to parse guest report");
let res = report.verify(Some(Policy::permissive())).await
.expect("failed to call verify");
if !res {
panic!("verification failed");
}
} ```
You may also use Policy::strict()
or make your own policy:
rust
let policy = Policy::new(
true, // require_no_debug
true, // require_no_ma
true, // require_no_smt
true, // require_id_key
true // require_author_key
);
You may also obtain the certificates to work with them directly:
```rust use sevsnputils::{ AttestationReport, KdsCertificates, CertFormat, getkdsarkaskcertsbytes, getkdsarkaskcerts, getkdsarkaskcertsandvalidate, validatearkaskvcekcerts, PRODUCTNAME_MILAN };
async fn getcerts() { let report = AttestationReport::fromfile("./guest_report.bin") .expect("failed to parse guest report");
// VCEK
// Raw bytes as PEM or DER (cached only on disk)
let pem_bytes = report.get_kds_vcek_cert_bytes(CertFormat::PEM).await
.expect("failed to get VCEK PEM");
let der_bytes = report.get_kds_vcek_cert_bytes(CertFormat::DER).await
.expect("failed to get VCEK DER");
// X509 (cached in-memory, prefer this method)
let cert = report.get_kds_vcek_cert().await
.expect("failed to get VCEK cert");
// ARK & ASK
// Raw bytes as PEM or DER (cached only on disk)
let (ark_pem, ask_pem) = get_kds_ark_ask_certs_bytes(PRODUCT_NAME_MILAN, CertFormat::PEM).await
.expect("failed to get ARK/ASK PEMs");
// X509 (cached in-memory, prefer this method)
let (ark_cert, ask_cert) = get_kds_ark_ask_certs(PRODUCT_NAME_MILAN).await
.expect("failed to get ARK/ASK certs");
// X509 validated (cached in-memory, prefer this method)
let (ark_cert, ask_cert) = get_kds_ark_ask_certs_and_validate(PRODUCT_NAME_MILAN).await
.expect("failed to get ARK/ASK certs");
// Validate
validate_ark_ask_vcek_certs(&ark_cert, &ask_cert, Some(&cert))
.expect("failed to validate certs");
} ```
```rust use std::fs; use std::path::PathBuf; use sevsnputils::{ calclaunchdigest, SevMode, CpuType };
fn main() { let ovmfpath = PathBuf::from("./OVMFCODE.fd"); let kernelpath = PathBuf::from("./vmlinuz"); let appendpath = PathBuf::from("./vmlinuz.cmdline"); let initrd_path = PathBuf::from("./initrd.img");
let append = fs::read_to_string(&append_path)
.expect(format!("failed to read '{:?}'", &append_path).as_str());
let digest = calc_launch_digest(SevMode::SevSnp, 64, ovmf_path.as_path(),
Some(kernel_path.as_path()), Some(initrd_path.as_path()),
Some(append.as_str()))
.expect("failed to calculate launch digest");
} ```
Before you can generate an IdBlock
and IdAuthInfo
you'll first need to create some ECDSA keys (pem files).
```shell openssl genpkey -algorithm ec -pkeyopt ecparamgencurve:"P-384" -out id-key.pem
openssl genpkey -algorithm ec -pkeyopt ecparamgencurve:"P-384" -out author-key.pem ```
```rust use std::path::PathBuf; use sevsnputils::{ createidentityblock, LaunchDigest, FamilyId, ImageId, ToBase64 };
fn main() { let idkeypem = PathBuf::from("./id-key.pem"); let authorkeypem = PathBuf::from("./author-key.pem");
let measurement = LaunchDigest::from_str("ffb0cb7f01a5d5b122430d66f211326ab5cf11a9a5d3189ec53adf9a60730bc63d9856fe9fe602abd662861d0ee36007");
let family_id = FamilyId::zeroes();
let image_id = ImageId::from_str("ffb0cb7f01a5d5b122430d66f211326a");
let guest_svn = 0;
let policy = 0x30000;
let (id_block, id_auth_info) = create_identity_block(measurement, family_id, image_id,
guest_svn, policy, id_key_pem.as_path(),
Some(author_key_pem.as_path()))
.expect("failed to create identity block");
println!("id_block: {}", id_block.to_base64().unwrap()); // Or call save_base64().
println!("id_auth_info: {}", id_auth_info.to_base64().unwrap());
} ```
```rust use std::path::PathBuf; use sevsnputils::{ IdBlock, LaunchDigest, FamilyId, ImageId, BlockSigner, ToBase64 };
fn main() { let idkeypem = PathBuf::from("./id-key.pem"); let authorkeypem = PathBuf::from("./author-key.pem");
let id_block = IdBlock::default()
.with_ld(LaunchDigest::from_str("ffb0cb7f01a5d5b122430d66f211326ab5cf11a9a5d3189ec53adf9a60730bc63d9856fe9fe602abd662861d0ee36007"))
.with_family_id(FamilyId::zeroes())
.with_image_id(ImageId::from_str("ffb0cb7f01a5d5b122430d66f211326a"))
.with_guest_svn(0)
.with_policy(0x30000);
let id_auth_info = id_block.sign(id_key_pem.as_path(), Some(author_key_pem.as_path()))
.expect("failed to sign id block");
println!("id_block: {}", id_block.to_base64().unwrap()); // Or call save_base64().
println!("id_auth_info: {}", id_auth_info.to_base64().unwrap());
} ```