Skip to content

Commit 236743f

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 236743f

File tree

8 files changed

+311
-87
lines changed

8 files changed

+311
-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: 38 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,8 @@ mod registration {
263270
use keylime::context_info::ContextInfo;
264271
use std::sync::{Arc, Mutex, OnceLock};
265272

273+
pub use crate::registration::RegistrarTlsConfig;
274+
266275
static MOCK_RESULT: OnceLock<Arc<Mutex<Result<(), String>>>> =
267276
OnceLock::new();
268277

@@ -272,6 +281,7 @@ mod registration {
272281

273282
pub async fn check_registration(
274283
_context_info: Option<ContextInfo>,
284+
_tls_config: Option<RegistrarTlsConfig>,
275285
) -> anyhow::Result<()> {
276286
let result = get_mock_result().lock().unwrap().clone();
277287
result.map_err(|e| anyhow!(e))
@@ -425,6 +435,7 @@ mod tpm_tests {
425435
neg_config.clone(),
426436
None,
427437
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
438+
None,
428439
),
429440
guard,
430441
);
@@ -437,6 +448,7 @@ mod tpm_tests {
437448
neg_config.clone(),
438449
Some(context_info),
439450
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
451+
None,
440452
),
441453
guard,
442454
)
@@ -611,9 +623,11 @@ mod tpm_tests {
611623
let mut context_info = sm.context_info.clone().unwrap();
612624

613625
registration::set_mock_result(Ok(()));
614-
let res =
615-
registration::check_registration(Some(context_info.clone()))
616-
.await;
626+
let res = registration::check_registration(
627+
Some(context_info.clone()),
628+
None,
629+
)
630+
.await;
617631

618632
match res {
619633
Ok(()) => {
@@ -654,8 +668,11 @@ mod tpm_tests {
654668
agent_data_path: "".to_string(),
655669
})
656670
.expect("This test requires TPM access with proper permissions");
657-
let _ = registration::check_registration(Some(context_info.clone()))
658-
.await;
671+
let _ = registration::check_registration(
672+
Some(context_info.clone()),
673+
None,
674+
)
675+
.await;
659676

660677
let mock_server = MockServer::start().await;
661678

@@ -704,6 +721,7 @@ mod tpm_tests {
704721
neg_config,
705722
Some(context_info.clone()),
706723
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
724+
None,
707725
);
708726

709727
// We can't easily test the full run() method since it loops indefinitely.
@@ -766,6 +784,7 @@ mod tests {
766784
test_config,
767785
None,
768786
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
787+
None,
769788
);
770789

771790
// Should start in Unregistered state when no context info is provided.
@@ -793,6 +812,7 @@ mod tests {
793812
test_config,
794813
None,
795814
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
815+
None,
796816
);
797817

798818
let debug_output = format!("{:?}", state_machine.get_current_state());
@@ -816,6 +836,7 @@ mod tests {
816836
test_config,
817837
None,
818838
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
839+
None,
819840
);
820841

821842
// Start in Unregistered state.
@@ -852,6 +873,7 @@ mod tests {
852873
test_config,
853874
None,
854875
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
876+
None,
855877
);
856878

857879
// Should start in Unregistered state.
@@ -878,6 +900,7 @@ mod tests {
878900
test_config,
879901
None,
880902
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
903+
None,
881904
);
882905

883906
// Verify that context_info is None when not provided.
@@ -901,6 +924,7 @@ mod tests {
901924
test_config,
902925
None,
903926
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
927+
None,
904928
);
905929

906930
// Test that the configuration references are stored correctly.
@@ -928,6 +952,7 @@ mod tests {
928952
test_config,
929953
None,
930954
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
955+
None,
931956
);
932957

933958
// Manually set to Failed state to test error handling.
@@ -959,6 +984,7 @@ mod tests {
959984
test_config,
960985
None,
961986
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
987+
None,
962988
);
963989

964990
// Manually set to Failed state to test error handling.
@@ -985,6 +1011,7 @@ mod tests {
9851011
test_config1,
9861012
None,
9871013
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1014+
None,
9881015
);
9891016
assert!(matches!(
9901017
state_machine1.get_current_state(),
@@ -1000,6 +1027,7 @@ mod tests {
10001027
test_config2,
10011028
None,
10021029
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1030+
None,
10031031
);
10041032
assert!(matches!(
10051033
state_machine2.get_current_state(),
@@ -1024,6 +1052,7 @@ mod tests {
10241052
test_config,
10251053
None,
10261054
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1055+
None,
10271056
);
10281057

10291058
// Test that avoid_tpm is properly configured through the test config.
@@ -1051,6 +1080,7 @@ mod tests {
10511080
test_config,
10521081
None,
10531082
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1083+
None,
10541084
);
10551085

10561086
// Set a test error and verify debug formatting works.
@@ -1083,6 +1113,7 @@ mod tests {
10831113
test_config,
10841114
None,
10851115
DEFAULT_ATTESTATION_INTERVAL_SECONDS,
1116+
None,
10861117
);
10871118

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

0 commit comments

Comments
 (0)