Skip to content

Commit 7dd9eed

Browse files
committed
empty TPM key-provider id for stable launch measurement
The TPM app-root public key is derived from a per-instance sealed seed, so measuring it as key-provider id made mr_system/mr_aggregated instance-bound and unusable as a precomputed allowlist identity. Emit and report an empty id for key_provider=tpm (mode remains in the event name / kind); KMS and local provider ids are unchanged.
1 parent 29e3563 commit 7dd9eed

4 files changed

Lines changed: 43 additions & 10 deletions

File tree

docs/security/cvm-boundaries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ This is the main configuration file for the application in JSON format:
3333
| kms_enabled | 0.3.1 | boolean | Enable/disable KMS |
3434
| gateway_enabled | 0.3.1 | boolean | Enable/disable gateway |
3535
| local_key_provider_enabled | 0.3.1 | boolean | Use a local key provider |
36-
| key_provider_id | 0.5.1 | string | Key provider ID. |
36+
| key_provider_id | 0.5.1 | string | Optional pin for the key provider identity. For `kms` this is the KMS CA public key; for `local` the sealing-provider MR. For `tpm` and `none` it is empty — the TPM app-root public key is instance-specific and is not used as a provider id or measured as one. |
3737
| public_logs | 0.3.3 | boolean | Whether logs are publicly visible |
3838
| public_sysinfo | 0.3.3 | boolean | Whether system info is public |
3939
| public_tcbinfo | 0.5.1 | boolean | Whether TCB info is public |

dstack/dstack-types/src/lib.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1390,11 +1390,19 @@ impl KeyProvider {
13901390
}
13911391
}
13921392

1393+
/// Stable key-provider identity used for launch measurement and compose pins.
1394+
///
1395+
/// - KMS: root CA public key
1396+
/// - Local: sealing-provider MR
1397+
/// - TPM: always empty — the derived app root pubkey is instance-specific
1398+
/// (from a TPM-sealed seed) and must not be treated as a stable provider id
1399+
/// or measured as one. Mode is already carried by [`Self::kind`].
1400+
/// - None: empty
13931401
pub fn id(&self) -> &[u8] {
13941402
match self {
13951403
KeyProvider::None { .. } => &[],
13961404
KeyProvider::Local { mr, .. } => mr,
1397-
KeyProvider::Tpm { pubkey, .. } => pubkey,
1405+
KeyProvider::Tpm { .. } => &[],
13981406
KeyProvider::Kms { pubkey, .. } => pubkey,
13991407
}
14001408
}
@@ -1412,6 +1420,31 @@ impl KeyProviderInfo {
14121420
}
14131421
}
14141422

1423+
#[cfg(test)]
1424+
mod key_provider_tests {
1425+
use super::*;
1426+
1427+
#[test]
1428+
fn tpm_key_provider_id_is_empty() {
1429+
let tpm = KeyProvider::Tpm {
1430+
key: "dummy".into(),
1431+
// Instance app-root pubkey may still be stored on the key handle, but
1432+
// it must not be reported as the stable provider id.
1433+
pubkey: vec![0x04; 65],
1434+
};
1435+
assert!(tpm.id().is_empty());
1436+
assert_eq!(tpm.kind(), KeyProviderKind::Tpm);
1437+
1438+
let kms = KeyProvider::Kms {
1439+
url: "https://kms.example".into(),
1440+
pubkey: vec![0xab; 32],
1441+
tmp_ca_key: String::new(),
1442+
tmp_ca_cert: String::new(),
1443+
};
1444+
assert_eq!(kms.id(), &[0xab; 32]);
1445+
}
1446+
}
1447+
14151448
#[derive(Debug, Clone, Serialize, Deserialize)]
14161449
pub struct ImageInfo {
14171450
pub cmdline: String,

dstack/dstack-util/src/system_setup.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,16 +1901,16 @@ impl<'a> Stage0<'a> {
19011901
keys.key_provider.id(),
19021902
)?;
19031903
self.verify_key_provider_id(keys.key_provider.id())?;
1904+
// TPM uses an empty id: the instance app-root pubkey is not a stable
1905+
// provider identity and must not enter the launch measurement chain.
19041906
let kp_info = match &keys.key_provider {
19051907
KeyProvider::None { .. } => KeyProviderInfo::new("none".into(), "".into()),
1906-
KeyProvider::Local { mr, .. } => {
1907-
KeyProviderInfo::new("local-sgx".into(), hex::encode(mr))
1908+
KeyProvider::Local { .. } => {
1909+
KeyProviderInfo::new("local-sgx".into(), hex::encode(keys.key_provider.id()))
19081910
}
1909-
KeyProvider::Tpm { pubkey, .. } => {
1910-
KeyProviderInfo::new("tpm".into(), hex::encode(pubkey))
1911-
}
1912-
KeyProvider::Kms { pubkey, .. } => {
1913-
KeyProviderInfo::new("kms".into(), hex::encode(pubkey))
1911+
KeyProvider::Tpm { .. } => KeyProviderInfo::new("tpm".into(), "".into()),
1912+
KeyProvider::Kms { .. } => {
1913+
KeyProviderInfo::new("kms".into(), hex::encode(keys.key_provider.id()))
19141914
}
19151915
};
19161916
emit_key_provider_info(&kp_info)?;

dstack/dstack-util/src/system_setup/config_id_verifier.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn read_snp_host_data() -> Result<[u8; 32]> {
6262
/// - compose_hash: [u8; 32]
6363
/// - app_id: [u8; 20]
6464
/// - key_provider_type: u8 // 0: none, 1: local, 2: kms, 3: tpm
65-
/// - key_provider_id: [u8] // the ca pubkey for KMS or the MR enclave for local-sgx provider, empty for none
65+
/// - key_provider_id: [u8] // KMS CA pubkey, local-sgx MR, or empty for none/tpm
6666
pub fn verify_mr_config_id(
6767
compose_hash: &[u8; 32],
6868
app_id: &[u8; 20],

0 commit comments

Comments
 (0)