Skip to content

Commit db59f9f

Browse files
sarroutbiclaude
andcommitted
Add TLS support for Registrar communication
This change enables TLS-based communication with the Registrar service in the push model agent, providing secure registration and activation. Key changes: - Added registrar_tls_enabled, registrar_tls_ca_cert, registrar_tls_client_cert, and registrar_tls_client_key configuration options with empty defaults for backwards compatibility - Updated RegistrarClientBuilder to accept TLS configuration parameters (ca_certificate, certificate, key, insecure, timeout) - Modified RegistrarClient to use HTTPS client when TLS is configured, falling back to plain HTTP when TLS parameters are not provided - Refactored to use single ResilientClient for all HTTP/HTTPS requests instead of maintaining separate client instances - Added RegistrarTlsConfig struct in push model agent to manage TLS configuration from config file - Updated StateMachine to accept and pass registrar_tls_config to registration functions Backwards compatibility: - Defaults to plain HTTP when registrar_tls_enabled is false (default) - Defaults to plain HTTP when TLS certificate paths are empty (default) - TLS only enabled when all three certificate paths are provided AND registrar_tls_enabled is true - Pull model agent unchanged - maintains existing behavior with None values for all new TLS fields The implementation separates Registrar TLS configuration from Verifier TLS configuration, allowing each service to be secured independently based on deployment requirements. Co-Authored-By: Claude <[email protected]> Signed-off-by: Sergio Arroutbi <[email protected]>
1 parent 672bc1b commit db59f9f

File tree

8 files changed

+317
-87
lines changed

8 files changed

+317
-87
lines changed

keylime-agent/src/main.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,12 @@ async fn main() -> Result<()> {
617617
registrar_port: config.registrar_port,
618618
enable_iak_idevid: config.enable_iak_idevid,
619619
ek_handle: config.ek_handle.clone(),
620+
// Pull model agent does not use TLS for registrar communication
621+
registrar_ca_cert: None,
622+
registrar_client_cert: None,
623+
registrar_client_key: None,
624+
registrar_insecure: None,
625+
registrar_timeout: None,
620626
};
621627

622628
let aa = AgentRegistration {

keylime-push-model-agent/src/main.rs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use anyhow::Result;
44
use clap::Parser;
55
use keylime::config::PushModelConfigTrait;
6-
use log::{debug, error, info};
6+
use log::{debug, error, info, warn};
77
mod attestation;
88
mod auth;
99
mod context_info_handler;
@@ -175,11 +175,39 @@ async fn run(args: &Args) -> Result<()> {
175175
};
176176
let attestation_client =
177177
attestation::AttestationClient::new(&neg_config)?;
178+
179+
// Create Registrar TLS config from configuration
180+
let registrar_tls_config = if config.registrar_tls_enabled() {
181+
let ca_cert = config.registrar_tls_ca_cert();
182+
let client_cert = config.registrar_tls_client_cert();
183+
let client_key = config.registrar_tls_client_key();
184+
185+
// Only use TLS if all certificate paths are provided
186+
if !ca_cert.is_empty()
187+
&& !client_cert.is_empty()
188+
&& !client_key.is_empty()
189+
{
190+
Some(registration::RegistrarTlsConfig {
191+
ca_cert: Some(ca_cert.to_string()),
192+
client_cert: Some(client_cert.to_string()),
193+
client_key: Some(client_key.to_string()),
194+
insecure: None,
195+
timeout: Some(args.timeout),
196+
})
197+
} else {
198+
warn!("Registrar TLS is enabled but certificate paths are not configured. Using plain HTTP.");
199+
None
200+
}
201+
} else {
202+
None
203+
};
204+
178205
let mut state_machine = state_machine::StateMachine::new(
179206
attestation_client,
180207
neg_config,
181208
ctx_info,
182209
args.attestation_interval_seconds,
210+
registrar_tls_config,
183211
);
184212
state_machine.run().await;
185213
Ok(())

keylime-push-model-agent/src/registration.rs

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,24 @@ use keylime::{
88
error::Result,
99
};
1010

11+
pub struct RegistrarTlsConfig {
12+
pub ca_cert: Option<String>,
13+
pub client_cert: Option<String>,
14+
pub client_key: Option<String>,
15+
pub insecure: Option<bool>,
16+
pub timeout: Option<u64>,
17+
}
18+
1119
pub async fn check_registration(
1220
context_info: Option<context_info::ContextInfo>,
21+
tls_config: Option<RegistrarTlsConfig>,
1322
) -> Result<()> {
1423
if context_info.is_some() {
15-
crate::registration::register_agent(&mut context_info.unwrap())
16-
.await?;
24+
crate::registration::register_agent(
25+
&mut context_info.unwrap(),
26+
tls_config,
27+
)
28+
.await?;
1729
}
1830
Ok(())
1931
}
@@ -41,9 +53,23 @@ fn get_retry_config() -> Option<RetryConfig> {
4153

4254
pub async fn register_agent(
4355
context_info: &mut context_info::ContextInfo,
56+
tls_config: Option<RegistrarTlsConfig>,
4457
) -> Result<()> {
4558
let config = keylime::config::get_config();
4659

60+
let (ca_cert, client_cert, client_key, insecure, timeout) =
61+
if let Some(tls) = tls_config {
62+
(
63+
tls.ca_cert,
64+
tls.client_cert,
65+
tls.client_key,
66+
tls.insecure,
67+
tls.timeout,
68+
)
69+
} else {
70+
(None, None, None, None, None)
71+
};
72+
4773
let ac = AgentRegistrationConfig {
4874
contact_ip: config.contact_ip().to_string(),
4975
contact_port: config.contact_port(),
@@ -55,6 +81,11 @@ pub async fn register_agent(
5581
.ek_handle()
5682
.expect("failed to get ek_handle")
5783
.to_string(),
84+
registrar_ca_cert: ca_cert,
85+
registrar_client_cert: client_cert,
86+
registrar_client_key: client_key,
87+
registrar_insecure: insecure,
88+
registrar_timeout: timeout,
5889
};
5990

6091
let cert_config = cert::CertificateConfig {
@@ -111,7 +142,7 @@ mod tests {
111142

112143
let tmpdir = tempfile::tempdir().expect("failed to create tempdir");
113144
let _config = get_testing_config(tmpdir.path(), None);
114-
let result = check_registration(None).await;
145+
let result = check_registration(None, None).await;
115146
assert!(result.is_ok());
116147
}
117148

@@ -136,7 +167,7 @@ mod tests {
136167

137168
let mut context_info = ContextInfo::new_from_str(alg_config)
138169
.expect("Failed to create context info from string");
139-
let result = register_agent(&mut context_info).await;
170+
let result = register_agent(&mut context_info, None).await;
140171
assert!(result.is_err());
141172
assert!(context_info.flush_context().is_ok());
142173
}

keylime-push-model-agent/src/state_machine.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::attestation::{
66
};
77
#[cfg(not(all(test, feature = "testing")))]
88
use crate::registration;
9+
use crate::registration::RegistrarTlsConfig;
910
#[cfg(test)]
1011
use crate::DEFAULT_ATTESTATION_INTERVAL_SECONDS;
1112
use anyhow::anyhow;
@@ -31,6 +32,7 @@ pub struct StateMachine<'a> {
3132
negotiation_config: NegotiationConfig<'a>,
3233
context_info: Option<ContextInfo>,
3334
measurement_interval: Duration,
35+
registrar_tls_config: Option<RegistrarTlsConfig>,
3436
}
3537

3638
impl<'a> StateMachine<'a> {
@@ -39,6 +41,7 @@ impl<'a> StateMachine<'a> {
3941
negotiation_config: NegotiationConfig<'a>,
4042
context_info: Option<ContextInfo>,
4143
attestation_interval_seconds: u64,
44+
registrar_tls_config: Option<RegistrarTlsConfig>,
4245
) -> Self {
4346
let initial_state = State::Unregistered;
4447
let measurement_interval =
@@ -50,6 +53,7 @@ impl<'a> StateMachine<'a> {
5053
negotiation_config,
5154
context_info,
5255
measurement_interval,
56+
registrar_tls_config,
5357
}
5458
}
5559

@@ -104,8 +108,11 @@ impl<'a> StateMachine<'a> {
104108
}
105109

106110
async fn register(&mut self) {
107-
let res =
108-
registration::check_registration(self.context_info.clone()).await;
111+
let res = registration::check_registration(
112+
self.context_info.clone(),
113+
self.registrar_tls_config.take(),
114+
)
115+
.await;
109116

110117
match res {
111118
Ok(()) => {
@@ -263,6 +270,14 @@ mod registration {
263270
use keylime::context_info::ContextInfo;
264271
use std::sync::{Arc, Mutex, OnceLock};
265272

273+
pub struct RegistrarTlsConfig {
274+
pub ca_cert: Option<String>,
275+
pub client_cert: Option<String>,
276+
pub client_key: Option<String>,
277+
pub insecure: Option<bool>,
278+
pub timeout: Option<u64>,
279+
}
280+
266281
static MOCK_RESULT: OnceLock<Arc<Mutex<Result<(), String>>>> =
267282
OnceLock::new();
268283

@@ -272,6 +287,7 @@ mod registration {
272287

273288
pub async fn check_registration(
274289
_context_info: Option<ContextInfo>,
290+
_tls_config: Option<RegistrarTlsConfig>,
275291
) -> anyhow::Result<()> {
276292
let result = get_mock_result().lock().unwrap().clone();
277293
result.map_err(|e| anyhow!(e))
@@ -425,6 +441,7 @@ mod tpm_tests {
425441
neg_config.clone(),
426442
None,
427443
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
444+
None,
428445
),
429446
guard,
430447
);
@@ -437,6 +454,7 @@ mod tpm_tests {
437454
neg_config.clone(),
438455
Some(context_info),
439456
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
457+
None,
440458
),
441459
guard,
442460
)
@@ -611,9 +629,11 @@ mod tpm_tests {
611629
let mut context_info = sm.context_info.clone().unwrap();
612630

613631
registration::set_mock_result(Ok(()));
614-
let res =
615-
registration::check_registration(Some(context_info.clone()))
616-
.await;
632+
let res = registration::check_registration(
633+
Some(context_info.clone()),
634+
None,
635+
)
636+
.await;
617637

618638
match res {
619639
Ok(()) => {
@@ -654,8 +674,11 @@ mod tpm_tests {
654674
agent_data_path: "".to_string(),
655675
})
656676
.expect("This test requires TPM access with proper permissions");
657-
let _ = registration::check_registration(Some(context_info.clone()))
658-
.await;
677+
let _ = registration::check_registration(
678+
Some(context_info.clone()),
679+
None,
680+
)
681+
.await;
659682

660683
let mock_server = MockServer::start().await;
661684

@@ -704,6 +727,7 @@ mod tpm_tests {
704727
neg_config,
705728
Some(context_info.clone()),
706729
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
730+
None,
707731
);
708732

709733
// We can't easily test the full run() method since it loops indefinitely.
@@ -766,6 +790,7 @@ mod tests {
766790
test_config,
767791
None,
768792
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
793+
None,
769794
);
770795

771796
// Should start in Unregistered state when no context info is provided.
@@ -793,6 +818,7 @@ mod tests {
793818
test_config,
794819
None,
795820
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
821+
None,
796822
);
797823

798824
let debug_output = format!("{:?}", state_machine.get_current_state());
@@ -816,6 +842,7 @@ mod tests {
816842
test_config,
817843
None,
818844
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
845+
None,
819846
);
820847

821848
// Start in Unregistered state.
@@ -852,6 +879,7 @@ mod tests {
852879
test_config,
853880
None,
854881
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
882+
None,
855883
);
856884

857885
// Should start in Unregistered state.
@@ -878,6 +906,7 @@ mod tests {
878906
test_config,
879907
None,
880908
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
909+
None,
881910
);
882911

883912
// Verify that context_info is None when not provided.
@@ -901,6 +930,7 @@ mod tests {
901930
test_config,
902931
None,
903932
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
933+
None,
904934
);
905935

906936
// Test that the configuration references are stored correctly.
@@ -928,6 +958,7 @@ mod tests {
928958
test_config,
929959
None,
930960
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
961+
None,
931962
);
932963

933964
// Manually set to Failed state to test error handling.
@@ -959,6 +990,7 @@ mod tests {
959990
test_config,
960991
None,
961992
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
993+
None,
962994
);
963995

964996
// Manually set to Failed state to test error handling.
@@ -985,6 +1017,7 @@ mod tests {
9851017
test_config1,
9861018
None,
9871019
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1020+
None,
9881021
);
9891022
assert!(matches!(
9901023
state_machine1.get_current_state(),
@@ -1000,6 +1033,7 @@ mod tests {
10001033
test_config2,
10011034
None,
10021035
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1036+
None,
10031037
);
10041038
assert!(matches!(
10051039
state_machine2.get_current_state(),
@@ -1024,6 +1058,7 @@ mod tests {
10241058
test_config,
10251059
None,
10261060
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1061+
None,
10271062
);
10281063

10291064
// Test that avoid_tpm is properly configured through the test config.
@@ -1051,6 +1086,7 @@ mod tests {
10511086
test_config,
10521087
None,
10531088
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1089+
None,
10541090
);
10551091

10561092
// Set a test error and verify debug formatting works.
@@ -1083,6 +1119,7 @@ mod tests {
10831119
test_config,
10841120
None,
10851121
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1122+
None,
10861123
);
10871124

10881125
// Test with valid seconds_to_next_attestation field in meta object.

0 commit comments

Comments
 (0)