Skip to content

Commit e16304e

Browse files
Xynnn007cursoragent
andcommitted
aa: let the KBC select attestation policies by id
Trustee gained a policy_id_map, with which an administrator maps an id that a client names in the RCAR Request to the Attestation Service policies that evaluate its evidence. Give the KBC a way to name such an id, so that a deployment can have different guests evaluated against different policies without running separate KBS instances. kbs_protocol carries the id from `KbsClientBuilder::set_id` into the `extra-params` of the auth Request. AA takes it from the new `id` field of the `[token_configs.kbs]` section, which is empty by default. An empty id is not sent at all: KBS falls back to a default policy for a Request without an id, but rejects the handshake of a client that sends an id the deployment does not declare. Configuring an id therefore only works against a KBS that maps it, which is why it stays opt-in and why the empty string, rather than an `Option`, expresses "not configured" in the config. Signed-off-by: Xynnn007 <xynnn@linux.alibaba.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 4032384 commit e16304e

8 files changed

Lines changed: 134 additions & 12 deletions

File tree

attestation-agent/attestation-agent/config.example.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ url = "http://127.0.0.1:8000"
66
[token_configs.kbs]
77
url = "https://127.0.0.1:8080"
88
tee_key_algorithm = "ECDH-ES+A256KW-P256"
9+
# Id which KBS resolves to the attestation policies that evaluate this guest's
10+
# evidence. Empty by default, which leaves the selection to KBS. The accepted
11+
# values are specific to a KBS deployment and an unknown id is rejected.
12+
# id = "alice"
913
cert = '''
1014
-----BEGIN CERTIFICATE-----
1115
MIIDljCCAn6gAwIBAgIUR/UNh13GFam4emgludtype/S9BIwDQYJKoZIhvcNAQEL

attestation-agent/attestation-agent/src/config/kbs.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ pub struct KbsConfig {
2020

2121
#[serde(default)]
2222
pub tee_key_algorithm: TeeKeyAlgorithm,
23+
24+
/// Id which KBS resolves to the attestation policies that evaluate this
25+
/// guest's evidence. The accepted values are specific to a KBS
26+
/// deployment, so this has to be agreed with the KBS administrator.
27+
///
28+
/// Empty by default, which leaves the policy selection to KBS. An empty
29+
/// id is not sent, because KBS rejects an id it does not know.
30+
#[serde(default)]
31+
pub id: String,
2332
}
2433

2534
impl KbsConfig {
@@ -35,6 +44,7 @@ impl KbsConfig {
3544
url: aa_kbc_params.uri,
3645
cert: None,
3746
tee_key_algorithm: TeeKeyAlgorithm::default(),
47+
id: String::new(),
3848
})
3949
}
4050
}

attestation-agent/attestation-agent/src/config/mod.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ M9QaC1mzQ/OStg==
182182
-----END CERTIFICATE-----
183183
".to_string()),
184184
tee_key_algorithm: kbs_protocol::TeeKeyAlgorithm::EcdhEsA256KwP256,
185+
id: String::new(),
185186
})
186187
},
187188
eventlog_config: EventlogConfig {
@@ -224,6 +225,7 @@ M9QaC1mzQ/OStg==
224225
-----END CERTIFICATE-----
225226
".to_string()),
226227
tee_key_algorithm: kbs_protocol::TeeKeyAlgorithm::EcdhEsA256KwP256,
228+
id: String::new(),
227229
})
228230
},
229231
eventlog_config: EventlogConfig {
@@ -245,6 +247,7 @@ M9QaC1mzQ/OStg==
245247
url: "https://127.0.0.1:8080".to_string(),
246248
cert: Some("cert".to_string()),
247249
tee_key_algorithm: kbs_protocol::TeeKeyAlgorithm::EcdhEsA256KwP256,
250+
id: String::new(),
248251
})
249252
},
250253
eventlog_config: EventlogConfig {
@@ -264,6 +267,27 @@ M9QaC1mzQ/OStg==
264267
url: "https://127.0.0.1:8080".to_string(),
265268
cert: Some("cert".to_string()),
266269
tee_key_algorithm: kbs_protocol::TeeKeyAlgorithm::EcdhEsA256KwP256,
270+
id: String::new(),
271+
})
272+
},
273+
eventlog_config: EventlogConfig {
274+
init_pcr: 17,
275+
enable_eventlog: false,
276+
},
277+
log: LogConfig { level: "warn".to_string() },
278+
})]
279+
#[case(
280+
"test/config7.toml",
281+
Config {
282+
token_configs: TokenConfigs {
283+
#[cfg(feature = "coco_as")]
284+
coco_as: None,
285+
#[cfg(feature = "kbs")]
286+
kbs: Some(crate::config::kbs::KbsConfig {
287+
url: "https://127.0.0.1:8080".to_string(),
288+
cert: Some("cert".to_string()),
289+
tee_key_algorithm: kbs_protocol::TeeKeyAlgorithm::EcdhEsA256KwP256,
290+
id: "alice".to_string(),
267291
})
268292
},
269293
eventlog_config: EventlogConfig {

attestation-agent/attestation-agent/src/token/kbs.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub struct KbsTokenGetter {
2020
kbs_host_url: String,
2121
cert: Option<String>,
2222
tee_key_algorithm: TeeKeyAlgorithm,
23+
id: String,
2324
}
2425

2526
impl KbsTokenGetter {
@@ -34,6 +35,10 @@ impl KbsTokenGetter {
3435
}
3536
builder = builder.set_tee_key_algorithm(self.tee_key_algorithm);
3637

38+
if !self.id.is_empty() {
39+
builder = builder.set_id(&self.id);
40+
}
41+
3742
if let Some(initdata) = initdata {
3843
builder = builder.add_initdata(initdata.to_string());
3944
}
@@ -57,6 +62,7 @@ impl KbsTokenGetter {
5762
kbs_host_url: config.url.clone(),
5863
cert: config.cert.clone(),
5964
tee_key_algorithm: config.tee_key_algorithm,
65+
id: config.id.clone(),
6066
}
6167
}
6268
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[log]
2+
level = "warn"
3+
4+
[token_configs]
5+
[token_configs.kbs]
6+
url = "https://127.0.0.1:8080"
7+
cert = "cert"
8+
id = "alice"
9+
10+
[eventlog_config]
11+
init_pcr = 17
12+
enable_eventlog = false

attestation-agent/kbs_protocol/src/builder.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub struct KbsClientBuilder<T> {
2727
tee_key: Option<String>,
2828
tee_key_algorithm: TeeKeyAlgorithm,
2929
initdata: Option<String>,
30+
id: Option<String>,
3031
}
3132

3233
impl KbsClientBuilder<Box<dyn EvidenceProvider>> {
@@ -42,6 +43,7 @@ impl KbsClientBuilder<Box<dyn EvidenceProvider>> {
4243
tee_key: None,
4344
tee_key_algorithm: TeeKeyAlgorithm::default(),
4445
initdata: None,
46+
id: None,
4547
}
4648
}
4749
}
@@ -56,6 +58,7 @@ impl KbsClientBuilder<Box<dyn TokenProvider>> {
5658
tee_key: None,
5759
tee_key_algorithm: TeeKeyAlgorithm::default(),
5860
initdata: None,
61+
id: None,
5962
}
6063
}
6164
}
@@ -86,6 +89,18 @@ impl<T> KbsClientBuilder<T> {
8689
self
8790
}
8891

92+
/// Set the id which KBS resolves to the attestation policies that
93+
/// evaluate this client's evidence.
94+
///
95+
/// The accepted values are specific to a KBS deployment, so an id has to
96+
/// be known in advance. KBS rejects the RCAR handshake of a client that
97+
/// sends an id it does not know, while a client that sends no id at all
98+
/// is evaluated against the default policy.
99+
pub fn set_id(mut self, id: &str) -> Self {
100+
self.id = Some(id.to_string());
101+
self
102+
}
103+
89104
pub fn build(self) -> Result<KbsClient<T>> {
90105
let mut http_client_builder = reqwest::Client::builder()
91106
.cookie_store(true)
@@ -126,6 +141,7 @@ impl<T> KbsClientBuilder<T> {
126141
.context("Build KBS http client")?,
127142
kbs_host_url: self.kbs_host_url,
128143
_initdata: self.initdata,
144+
_id: self.id,
129145
};
130146

131147
Ok(client)
@@ -163,4 +179,23 @@ x13TMfDeczAFBgMrZXADQQBpP6ABBkzVj3mF55nWUtP5vxwq3t91wqQJ6NyC7WsT
163179
.build()
164180
.expect("build client failed");
165181
}
182+
183+
#[rstest]
184+
#[case(None)]
185+
#[case(Some("alice"))]
186+
#[tokio::test]
187+
async fn test_build_client_with_id(#[case] id: Option<&str>) {
188+
let mut builder = KbsClientBuilder::with_evidence_provider(
189+
Box::<MockedEvidenceProvider>::default(),
190+
"test.io",
191+
);
192+
193+
if let Some(id) = id {
194+
builder = builder.set_id(id);
195+
}
196+
197+
let client = builder.build().expect("build client failed");
198+
199+
assert_eq!(client._id.as_deref(), id);
200+
}
166201
}

attestation-agent/kbs_protocol/src/client/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ pub struct KbsClient<T> {
4949

5050
/// initdata toml plaintext (if any)
5151
pub(crate) _initdata: Option<String>,
52+
53+
/// id selecting the attestation policies that evaluate this client's
54+
/// evidence (if any)
55+
pub(crate) _id: Option<String>,
5256
}
5357

5458
pub const KBS_PROTOCOL_VERSION: &str = "0.4.0";

attestation-agent/kbs_protocol/src/client/rcar_client.rs

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ const RCAR_RETRY_TIMEOUT_SECOND: u64 = 1;
3838
/// JSON object added to a 'Request's extra parameters.
3939
const SUPPORTED_HASH_ALGORITHMS_JSON_KEY: &str = "supported-hash-algorithms";
4040

41+
/// JSON key in a 'Request's extra parameters with which the client selects
42+
/// the attestation policies that evaluate its evidence.
43+
const ID_JSON_KEY: &str = "id";
44+
4145
/// JSON object returned in the Challenge whose value is based on
4246
/// SUPPORTED_HASH_ALGORITHMS_JSON_KEY and the TEE.
4347
const SELECTED_HASH_ALGORITHM_JSON_KEY: &str = "selected-hash-algorithm";
@@ -54,10 +58,14 @@ struct AttestationResponseData {
5458
token: String,
5559
}
5660

57-
async fn get_request_extra_params() -> serde_json::Value {
61+
async fn get_request_extra_params(id: Option<&str>) -> serde_json::Value {
5862
let supported_hash_algorithms = HashAlgorithm::list_all();
5963

60-
let extra_params = json!({SUPPORTED_HASH_ALGORITHMS_JSON_KEY: supported_hash_algorithms});
64+
let mut extra_params = json!({SUPPORTED_HASH_ALGORITHMS_JSON_KEY: supported_hash_algorithms});
65+
66+
if let Some(id) = id {
67+
extra_params[ID_JSON_KEY] = json!(id);
68+
}
6169

6270
extra_params
6371
}
@@ -86,8 +94,8 @@ fn serialize_json_canonically<T: Serialize>(value: T) -> anyhow::Result<Vec<u8>>
8694
Ok(serde_json_canonicalizer::to_vec(&value)?)
8795
}
8896

89-
async fn build_request(tee: Tee) -> Request {
90-
let extra_params = get_request_extra_params().await;
97+
async fn build_request(tee: Tee, id: Option<&str>) -> Request {
98+
let extra_params = get_request_extra_params(id).await;
9199

92100
// Note that the Request includes the list of supported hash algorithms.
93101
// The Challenge response will return which TEE-specific algorithm should
@@ -230,7 +238,7 @@ impl KbsClient<Box<dyn EvidenceProvider>> {
230238
ClientTee::_Initialized(tee) => *tee,
231239
};
232240

233-
let request = build_request(tee).await;
241+
let request = build_request(tee, self._id.as_deref()).await;
234242

235243
debug!("send auth request {request:?} to {auth_endpoint}");
236244

@@ -417,8 +425,8 @@ mod test {
417425

418426
use crate::client::rcar_client::{
419427
build_request, get_hash_algorithm, get_request_extra_params, Result,
420-
DEFAULT_HASH_ALGORITHM, KBS_PROTOCOL_VERSION, SELECTED_HASH_ALGORITHM_JSON_KEY,
421-
SUPPORTED_HASH_ALGORITHMS_JSON_KEY,
428+
DEFAULT_HASH_ALGORITHM, ID_JSON_KEY, KBS_PROTOCOL_VERSION,
429+
SELECTED_HASH_ALGORITHM_JSON_KEY, SUPPORTED_HASH_ALGORITHMS_JSON_KEY,
422430
};
423431
use kbs_types::Tee;
424432

@@ -540,13 +548,22 @@ mod test {
540548
println!("Get key: {key:?}");
541549
}
542550

551+
#[rstest]
552+
#[case(None)]
553+
#[case(Some("alice"))]
543554
#[tokio::test]
544555
#[serial_test::serial]
545-
async fn test_get_request_extra_params() {
546-
let extra_params = get_request_extra_params().await;
556+
async fn test_get_request_extra_params(#[case] id: Option<&str>) {
557+
let extra_params = get_request_extra_params(id).await;
547558

548559
assert!(extra_params.is_object());
549560

561+
assert_eq!(
562+
extra_params.get(ID_JSON_KEY).and_then(Value::as_str),
563+
id,
564+
"the id is only sent when it is set"
565+
);
566+
550567
let algos_json = extra_params
551568
.get(SUPPORTED_HASH_ALGORITHMS_JSON_KEY)
552569
.unwrap();
@@ -565,9 +582,12 @@ mod test {
565582
}
566583
}
567584

585+
#[rstest]
586+
#[case(None)]
587+
#[case(Some("alice"))]
568588
#[tokio::test]
569589
#[serial_test::serial]
570-
async fn test_build_request() {
590+
async fn test_build_request(#[case] id: Option<&str>) {
571591
let tees = vec![
572592
Tee::AzSnpVtpm,
573593
Tee::AzTdxVtpm,
@@ -580,14 +600,21 @@ mod test {
580600
];
581601

582602
let expected_version = String::from(KBS_PROTOCOL_VERSION);
583-
let expected_extra_params = get_request_extra_params().await;
603+
let expected_extra_params = get_request_extra_params(id).await;
584604

585605
for tee in tees {
586-
let request = build_request(tee).await;
606+
let request = build_request(tee, id).await;
587607

588608
assert_eq!(request.version, expected_version);
589609
assert_eq!(request.tee, tee);
590610
assert_eq!(request.extra_params, expected_extra_params);
611+
assert_eq!(
612+
request
613+
.extra_params
614+
.get(ID_JSON_KEY)
615+
.and_then(Value::as_str),
616+
id
617+
);
591618
}
592619
}
593620

0 commit comments

Comments
 (0)