Skip to content

Commit 100393a

Browse files
committed
fix: unify RA-TLS cert attestation format and fix onboard os_image_hash
Two changes: 1. ra-tls: use unified PHALA_RATLS_ATTESTATION OID for TDX certs instead of the legacy separate TDX_QUOTE + EVENT_LOG OIDs. The new format preserves vm_config (including os_image_hash). The reader already prefers the new format and falls back to old OIDs for backward compat. 2. kms: when the remote source KMS uses the old cert format (missing vm_config), the receiver-side onboard check fills os_image_hash from the local KMS's own value. This is safe because mrAggregated already validates OS image integrity through the RTMR measurement chain. This workaround should be removed once all source KMS instances use the new cert format.
1 parent c241544 commit 100393a

File tree

3 files changed

+19
-22
lines changed

3 files changed

+19
-22
lines changed

kms/src/main_service/upgrade_authority.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,19 @@ pub(crate) async fn ensure_kms_allowed(
224224
cfg: &KmsConfig,
225225
attestation: &VerifiedAttestation,
226226
) -> Result<()> {
227-
let boot_info = build_boot_info(attestation, false, "")
227+
let mut boot_info = build_boot_info(attestation, false, "")
228228
.context("failed to build KMS boot info from attestation")?;
229+
// Workaround: old source KMS instances use the legacy cert format (separate TDX_QUOTE +
230+
// EVENT_LOG OIDs) which lacks vm_config, resulting in an empty os_image_hash.
231+
// Fill it from the local KMS's own value. This is safe because mrAggregated already
232+
// validates OS image integrity transitively through the RTMR measurement chain.
233+
// TODO: remove once all source KMS instances use the unified PHALA_RATLS_ATTESTATION format.
234+
if boot_info.os_image_hash.is_empty() {
235+
let local_info = local_kms_boot_info(cfg.pccs_url.as_deref())
236+
.await
237+
.context("failed to get local KMS boot info for os_image_hash fallback")?;
238+
boot_info.os_image_hash = local_info.os_image_hash;
239+
}
229240
let response = cfg
230241
.auth_api
231242
.is_app_allowed(&boot_info, true)

ra-tls/src/cert.rs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,11 @@ use x509_parser::x509::SubjectPublicKeyInfo;
2525

2626
use crate::oids::{
2727
PHALA_RATLS_APP_ID, PHALA_RATLS_APP_INFO, PHALA_RATLS_ATTESTATION, PHALA_RATLS_CERT_USAGE,
28-
PHALA_RATLS_EVENT_LOG, PHALA_RATLS_TDX_QUOTE,
2928
};
3029
use crate::traits::CertExt;
3130
#[cfg(feature = "quote")]
3231
use dstack_attest::attestation::QuoteContentType;
33-
use dstack_attest::attestation::{AppInfo, Attestation, AttestationQuote, VersionedAttestation};
32+
use dstack_attest::attestation::{AppInfo, Attestation, VersionedAttestation};
3433

3534
/// A CA certificate and private key.
3635
pub struct CaCert {
@@ -389,21 +388,8 @@ impl<Key> CertRequest<'_, Key> {
389388
add_ext(&mut params, PHALA_RATLS_CERT_USAGE, usage);
390389
}
391390
if let Some(ver_att) = self.attestation {
392-
let VersionedAttestation::V0 { attestation } = &ver_att;
393-
match &attestation.quote {
394-
AttestationQuote::DstackTdx(tdx_quote) => {
395-
// For backward compatibility, we serialize the quote to the classic oids.
396-
let event_log = serde_json::to_vec(&tdx_quote.event_log)
397-
.context("Failed to serialize event log")?;
398-
add_ext(&mut params, PHALA_RATLS_TDX_QUOTE, &tdx_quote.quote);
399-
add_ext(&mut params, PHALA_RATLS_EVENT_LOG, &event_log);
400-
}
401-
_ => {
402-
// The event logs are too large on GCP TDX to put in the certificate, so we strip them
403-
let attestation_bytes = ver_att.clone().into_stripped().to_scale();
404-
add_ext(&mut params, PHALA_RATLS_ATTESTATION, &attestation_bytes);
405-
}
406-
}
391+
let attestation_bytes = ver_att.clone().into_stripped().to_scale();
392+
add_ext(&mut params, PHALA_RATLS_ATTESTATION, &attestation_bytes);
407393
}
408394
if let Some(ca_level) = self.ca_level {
409395
params.is_ca = IsCa::Ca(BasicConstraints::Constrained(ca_level));
@@ -576,7 +562,7 @@ pub fn generate_ra_cert_with_app_id(
576562
#[cfg(test)]
577563
mod tests {
578564
use super::*;
579-
use dstack_attest::attestation::TdxQuote;
565+
use dstack_attest::attestation::{AttestationQuote, TdxQuote};
580566
use rcgen::PKCS_ECDSA_P256_SHA256;
581567
use scale::Encode;
582568

tests/docs/kms-self-authorization.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This document describes a manual, AI-executable integration test flow for KMS self-authorization and quote-required KMS behavior.
44

5-
The goal is to validate the following behaviors:
5+
The goal is to validate the following behaviors without depending on `kms/e2e/` from PR #538:
66

77
1. **Bootstrap self-check**: a KMS must call the auth API and verify that **itself** is allowed before bootstrap succeeds.
88
2. **Onboard receiver-side source check**: a new KMS must reject onboarding if the **source KMS** is not allowed by the receiver's auth policy.
@@ -25,7 +25,7 @@ This guide is written as a deployment-and-test runbook so an AI agent can follow
2525
> 7. KMS now always requires quote/attestation. For local development without TDX hardware, use `sdk/simulator` instead of trying to run a no-attestation KMS flow.
2626
> 8. For `auth-simple`, `kms.mrAggregated = []` is a deny-all policy for KMS. Use that as the baseline deny configuration, then add the measured KMS MR values for allow cases.
2727
> 9. **Port forwarding is simpler than gateway for testing.** Using `--gateway` requires the auth API to return a valid `gatewayAppId`, which adds unnecessary complexity. Use `--port tcp:0.0.0.0:<host-port>:8000` instead.
28-
> 10. **~~Remote KMS attestation has an empty `osImageHash`.~~** Fixed in PR #581: RA-TLS certs now use the unified `PHALA_RATLS_ATTESTATION` format which preserves `vm_config`. For old source KMS instances that still use the legacy cert format, the receiver-side check automatically fills `osImageHash` from the local KMS's own value. No special `"0x"` entry in `osImages` is needed anymore.
28+
> 10. **~~Remote KMS attestation has an empty `osImageHash`.~~** Fixed: RA-TLS certs now use the unified `PHALA_RATLS_ATTESTATION` format which preserves `vm_config`. For old source KMS instances that still use the legacy cert format, the receiver-side `ensure_kms_allowed` automatically fills `osImageHash` from the local KMS's own value. No special `"0x"` entry in `osImages` is needed anymore.
2929
> 11. The `source_url` in the `Onboard.Onboard` request must use an address **reachable from inside the CVM** (e.g., `https://10.0.2.2:<port>/prpc`), not `127.0.0.1` which is the CVM's own loopback.
3030
3131
---
@@ -98,7 +98,7 @@ Policy responsibilities:
9898

9999
Before starting, make sure the following are available:
100100

101-
1. A KMS image built from current `master` (includes PR #573 auth checks, #579 mandatory attestation, #581 unified cert format)
101+
1. A KMS image built from current `master` (includes PR #573 auth checks, #579 mandatory attestation, #581 dedup refactor)
102102
2. A working `dstack-vmm` or teepod deployment target
103103
3. Two routable KMS onboard URLs
104104
4. `bun` installed on the host, because `kms/auth-simple` runs on Bun

0 commit comments

Comments
 (0)