{"id":24988506,"url":"https://github.com/lit-protocol/sev-snp-utils","last_synced_at":"2025-09-02T23:36:46.872Z","repository":{"id":61076580,"uuid":"546301671","full_name":"LIT-Protocol/sev-snp-utils","owner":"LIT-Protocol","description":"AMD SEV-SNP rust utils","archived":false,"fork":false,"pushed_at":"2025-04-07T18:13:28.000Z","size":39810,"stargazers_count":13,"open_issues_count":3,"forks_count":5,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-12T00:08:13.445Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LIT-Protocol.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-10-05T21:44:00.000Z","updated_at":"2025-03-18T18:57:04.000Z","dependencies_parsed_at":"2022-10-09T14:17:49.104Z","dependency_job_id":"61b1bf5b-4e84-4fc3-8af3-41d4a0e5c569","html_url":"https://github.com/LIT-Protocol/sev-snp-utils","commit_stats":{"total_commits":81,"total_committers":2,"mean_commits":40.5,"dds":"0.13580246913580252","last_synced_commit":"179347f2a148befef8f9fb2ddb8e7a90d97741f2"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIT-Protocol%2Fsev-snp-utils","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIT-Protocol%2Fsev-snp-utils/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIT-Protocol%2Fsev-snp-utils/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LIT-Protocol%2Fsev-snp-utils/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LIT-Protocol","download_url":"https://codeload.github.com/LIT-Protocol/sev-snp-utils/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248497810,"owners_count":21113984,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-04T12:04:30.921Z","updated_at":"2025-04-12T00:08:27.638Z","avatar_url":"https://github.com/LIT-Protocol.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sev-snp-utilities\n\nAMD SEV-SNP rust utils and primitives.\n\n## Testing\n\nInstead of `cargo test`, run:\n\n```shell\nmake test\n```\n\n## Environment\n\n| Variable                   | Default            | Description                                   |\n|----------------------------|--------------------|-----------------------------------------------|\n| SEV_SNP_CACHE_PATH         | /var/cache/sev-snp | Path to store downloaded certs.               |\n| SEV_SNP_CACHE_ENTRIES_VCEK | 100                | Max cache entries for VCEK certs (in-memory). |\n\n## Attestation\n\n### Report\n\n#### Request\n\nTo request a report from a SEV-SNP capable CPU (the same functionality as `sev-guest-get-report`):\n\n```rust\nuse sev_snp_utilities::{AttestationReport, Requester};\n\nfn main() {\n    let report = AttestationReport::request()\n        .expect(\"failed to request guest report\");\n\n    println!(\"version: {:?}\", report.version);\n    \n    // Or raw bytes\n    let report_bytes = AttestationReport::request_raw()\n        .expect(\"failed to request guest report\");\n\n    println!(\"bytes len: {:?}\", report_bytes.len());\n}\n```\n\n#### Parsing\n\nParse a guest_report.bin file from `sev-guest-get-report` (or one saved from `AttestationReport::request_raw()`):\n\n```rust\nuse sev_snp_utilities::AttestationReport;\n\nfn main() {\n    let report = AttestationReport::from_file(\"./guest_report.bin\")\n        .expect(\"failed to parse guest report\");\n    \n    println!(\"version: {:?}\", report.version);\n    println!(\"guest_svn: {:?}\", report.guest_svn);\n    println!(\"policy: {:?}\", report.policy);\n    println!(\"platform_version: {:?}\", report.platform_version.raw_decimal());\n    println!(\"measurement: {}\", report.measurement_hex());\n    println!(\"report data: {}\", report.report_data_hex());\n    println!(\"id key digest: {}\", report.id_key_digest_hex());\n    println!(\"author key digest: {}\", report.author_key_digest_hex());\n    println!(\"chip id: {}\", report.chip_id_hex());\n    println!(\"hash: {}\", report.sha384_hex());\n    println!(\"signature:\");\n    println!(\"  r: {}\", report.signature.r_hex());\n    println!(\"  s: {}\", report.signature.s_hex());\n}\n```\n\n#### Verification\n\nThe verification process:\n\n- Download the ARK, ASK and VCEK DER files from AMD and store them on disk (with in-memory cache as well).\n- Downloads are attempted multiple times (10 times with a 4sec sleep) as the ARK end-point is rate limited.\n- Verify that the ARK is self-signed, the ASK (AMD SEV intermediate cert) is signed by the ARK and that the VCEK (the CPU cert) is signed by the ASK.\n- Take a SHA384 hash of the first part of the report bin (before the signature).\n- Verifies the hash against the signature on the file against the cert chain.\n- Optionally validate some other things as per the Policy you provide.\n\nVerify a guest_report.bin file:\n\n```rust\nuse sev_snp_utilities::{AttestationReport, Verification, Policy};\n\nasync fn verify_guest() {\n    let report = AttestationReport::from_file(\"./guest_report.bin\")\n        .expect(\"failed to parse guest report\");\n\n    let res = report.verify(Some(Policy::permissive())).await\n        .expect(\"failed to call verify\");\n    \n    if !res {\n        panic!(\"verification failed\");\n    }\n}\n```\n\nYou may also use `Policy::strict()` or make your own policy:\n\n```rust\nlet policy = Policy::new(\n  true, // require_no_debug\n  true, // require_no_ma\n  true, // require_no_smt\n  true, // require_id_key\n  true  // require_author_key\n);\n```\n\n#### Certs\n\nYou may also obtain the certificates to work with them directly:\n\n```rust\nuse sev_snp_utilities::{\n    AttestationReport, KdsCertificates, CertFormat,\n    get_kds_ark_ask_certs_bytes, get_kds_ark_ask_certs,\n    get_kds_ark_ask_certs_and_validate, validate_ark_ask_vcek_certs,\n    PRODUCT_NAME_MILAN\n};\n\nasync fn get_certs() {\n    let report = AttestationReport::from_file(\"./guest_report.bin\")\n        .expect(\"failed to parse guest report\");\n\n    // VCEK\n    \n    // Raw bytes as PEM or DER (cached only on disk)\n    let pem_bytes = report.get_kds_vcek_cert_bytes(CertFormat::PEM).await\n        .expect(\"failed to get VCEK PEM\");\n\n    let der_bytes = report.get_kds_vcek_cert_bytes(CertFormat::DER).await\n        .expect(\"failed to get VCEK DER\");\n\n    // X509 (cached in-memory, prefer this method)\n    let cert = report.get_kds_vcek_cert().await\n        .expect(\"failed to get VCEK cert\");\n    \n    // ARK \u0026 ASK\n\n    // Raw bytes as PEM or DER (cached only on disk)\n    let (ark_pem, ask_pem) = get_kds_ark_ask_certs_bytes(PRODUCT_NAME_MILAN, CertFormat::PEM).await\n        .expect(\"failed to get ARK/ASK PEMs\");\n\n    // X509 (cached in-memory, prefer this method)\n    let (ark_cert, ask_cert) = get_kds_ark_ask_certs(PRODUCT_NAME_MILAN).await\n        .expect(\"failed to get ARK/ASK certs\");\n\n    // X509 validated (cached in-memory, prefer this method)\n    let (ark_cert, ask_cert) = get_kds_ark_ask_certs_and_validate(PRODUCT_NAME_MILAN).await\n        .expect(\"failed to get ARK/ASK certs\");\n    \n    // Validate\n    validate_ark_ask_vcek_certs(\u0026ark_cert, \u0026ask_cert, Some(\u0026cert))\n        .expect(\"failed to validate certs\");\n}\n```\n\n## Measurement\n\n### Calculating launch digest\n\n```rust\nuse std::fs;\nuse std::path::PathBuf;\nuse sev_snp_utilities::{\n    calc_launch_digest, SevMode, CpuType\n};\n\nfn main() {\n    let ovmf_path = PathBuf::from(\"./OVMF_CODE.fd\");\n    let kernel_path = PathBuf::from(\"./vmlinuz\");\n    let append_path = PathBuf::from(\"./vmlinuz.cmdline\");\n    let initrd_path = PathBuf::from(\"./initrd.img\");\n\n    let append = fs::read_to_string(\u0026append_path)\n        .expect(format!(\"failed to read '{:?}'\", \u0026append_path).as_str());\n    \n    let digest = calc_launch_digest(SevMode::SevSnp, 64, ovmf_path.as_path(),\n                                    Some(kernel_path.as_path()), Some(initrd_path.as_path()), \n                                    Some(append.as_str()))\n        .expect(\"failed to calculate launch digest\");\n}\n```\n\n## Identity\n\n### Preparation\n\nBefore you can generate an `IdBlock` and `IdAuthInfo` you'll first need to create some ECDSA keys (pem files).\n\n```shell\nopenssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:\"P-384\" -out id-key.pem\n\n# Author key is optional.\nopenssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:\"P-384\" -out author-key.pem\n```\n\n### Generating\n\n#### Method interface\n\n```rust\nuse std::path::PathBuf;\nuse sev_snp_utilities::{\n    create_identity_block, LaunchDigest, FamilyId, ImageId, ToBase64\n};\n\nfn main() {\n    let id_key_pem = PathBuf::from(\"./id-key.pem\");\n    let author_key_pem = PathBuf::from(\"./author-key.pem\");\n\n    let measurement = LaunchDigest::from_str(\"ffb0cb7f01a5d5b122430d66f211326ab5cf11a9a5d3189ec53adf9a60730bc63d9856fe9fe602abd662861d0ee36007\");\n    let family_id = FamilyId::zeroes();\n    let image_id = ImageId::from_str(\"ffb0cb7f01a5d5b122430d66f211326a\");\n    let guest_svn = 0;\n    let policy = 0x30000;\n    \n    let (id_block, id_auth_info) = create_identity_block(measurement, family_id, image_id,\n                                                         guest_svn, policy, id_key_pem.as_path(),\n                                                         Some(author_key_pem.as_path()))\n        .expect(\"failed to create identity block\");\n    \n    println!(\"id_block: {}\", id_block.to_base64().unwrap()); // Or call save_base64().\n    println!(\"id_auth_info: {}\", id_auth_info.to_base64().unwrap());\n}\n```\n\n#### Object interface\n\n```rust\nuse std::path::PathBuf;\nuse sev_snp_utilities::{\n    IdBlock, LaunchDigest, FamilyId, ImageId, BlockSigner, ToBase64\n};\n\nfn main() {\n    let id_key_pem = PathBuf::from(\"./id-key.pem\");\n    let author_key_pem = PathBuf::from(\"./author-key.pem\");\n\n    let id_block = IdBlock::default()\n        .with_ld(LaunchDigest::from_str(\"ffb0cb7f01a5d5b122430d66f211326ab5cf11a9a5d3189ec53adf9a60730bc63d9856fe9fe602abd662861d0ee36007\"))\n        .with_family_id(FamilyId::zeroes())\n        .with_image_id(ImageId::from_str(\"ffb0cb7f01a5d5b122430d66f211326a\"))\n        .with_guest_svn(0)\n        .with_policy(0x30000);\n\n    let id_auth_info = id_block.sign(id_key_pem.as_path(), Some(author_key_pem.as_path()))\n        .expect(\"failed to sign id block\");\n    \n    println!(\"id_block: {}\", id_block.to_base64().unwrap()); // Or call save_base64().\n    println!(\"id_auth_info: {}\", id_auth_info.to_base64().unwrap());\n}\n```\n\n### Fingerprints\n\n```rust\nuse std::path::PathBuf;\nuse sev_snp_utilities::{\n    fingerprint_id_key_as_hex\n};\n\nfn main() {\n    let id_key_pem = PathBuf::from(\"./id-key.pem\");\n    let author_key_pem = PathBuf::from(\"./author-key.pem\");\n\n    let id_fingerprint = fingerprint_id_key_as_hex(id_key_pem.as_path()) // or fingerprint_id_key()\n        .expect(\"failed to fingerprint\");\n    let author_fingerprint = fingerprint_id_key_as_hex(author_key_pem.as_path())\n        .expect(\"failed to fingerprint\");\n    \n    println!(\"id_fingerprint: {}\", id_fingerprint);\n    println!(\"author_fingerprint: {}\", author_fingerprint);\n}\n```\n\n## Key Derivation\n\nThe guest can ask the firmware to provide a key derived from a root key contained within the AMD SEV-SNP PSP. This key may be used by the guest for any purpose it chooses, such as sealing keys (i.e. for disk encryption) or communicating with external entities. Usually the intention will be that this can be used to create a key that's only known to the guest.\n\n### Preparation\n\nPrepare the request using `DerivedKeyRequestedBuilder` like so:\n\n```rust\nlet options = DerivedKeyRequestBuilder::new()\n    .with_tcb_version()\n    .with_image_id()\n    .build();\n```\n\nThe example above mixes the TCB version provided by the guest and the image ID provided at launch into the derived key.\n\nHere is the complete list of builder methods you can use to mix different data into the derived key:\n\n- `with_tcb_version`: mixes in the TCB version provided by the guest.\n- `with_svn`: mixes in the SVN of the guest.\n- `with_launch_measurement`: mixes in the measurement of the guest at launch.\n- `with_family_id`: mixes in the family ID at launch.\n- `with_image_id`: mixes in the image ID at launch.\n- `with_policy`: mixes in the guest policy at launch.\n\n### Request\n\nPass in the `DerivedKeyRequestOptions` struct to the `DerivedKey::request` method like so:\n\n```rust\nlet derived_key = DerivedKey::request(options).unwrap();\n```\n\n### Examples\n\nHere is a MCVE of how to request a derived key from the firmware:\n\n```rust\nuse sev_snp_utilities::guest::derived_key::get_derived_key::{DerivedKeyRequester, DerivedKeyRequestBuilder};\nuse sev_snp_utilities::guest::derived_key::derived_key::DerivedKey;\n\nfn main() {\n    let options = DerivedKeyRequestBuilder::new()\n        .with_tcb_version()\n        .with_image_id()\n        .build();\n    println!(\"Options: {:?}\", options);\n\n    let derived_key = DerivedKey::request(options).unwrap();\n    println!(\"Derived Key: {:?}\", derived_key);\n}\n```\n\n## Misc\n\n- AMD SEV-SNP Firmware ABI Specification: https://www.amd.com/system/files/TechDocs/56860.pdf","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flit-protocol%2Fsev-snp-utils","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flit-protocol%2Fsev-snp-utils","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flit-protocol%2Fsev-snp-utils/lists"}