Skip to content

Commit a13e173

Browse files
feat: add authentication client with middleware integration
Implement complete authentication system with challenge-response protocol, TPM2_Certify-based proof-of-possession, automatic token management, and configurable TLS security (secure by default). - AuthenticationClient with configurable API versioning (default: v3.0) - Authentication middleware for ResilientClient with auto token refresh - Async TPM operations trait with mock and real implementations - JSON:API compliant serialization and graceful unenrolled agent handling - Automatic retry with exponential backoff on authentication failures - Configurable TLS certificate validation (default: secure, opt-in insecure for testing) - Security warnings emitted once at agent startup when insecure TLS settings enabled Assisted-by: Claude 4 Sonnet Signed-off-by: Sergio Correia <[email protected]>
1 parent fb2b083 commit a13e173

File tree

18 files changed

+2296
-787
lines changed

18 files changed

+2296
-787
lines changed

Cargo.lock

Lines changed: 61 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

keylime-agent.conf

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,13 @@ measuredboot_ml_path = "default"
368368
# To override attestation_interval_seconds, set
369369
# KEYLIME_AGENT_ATTESTATION_INTERVAL_SECONDS environment variable.
370370
attestation_interval_seconds = 60
371+
372+
# Enable challenge-response authentication for push model attestation.
373+
# When enabled, the agent will authenticate with the verifier using TPM-based
374+
# proof of possession before sending attestation evidence.
375+
# This option is specific to the push attestation model.
376+
# The default is false (disabled).
377+
#
378+
# To override enable_authentication, set
379+
# KEYLIME_AGENT_ENABLE_AUTHENTICATION environment variable.
380+
enable_authentication = false

keylime-push-model-agent/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ url.workspace = true
3131
actix-rt.workspace = true
3232
tempfile.workspace = true
3333
wiremock = {version = "0.6"}
34+
# Dependencies for examples (auth_test)
35+
tracing = "0.1"
36+
tracing-subscriber = "0.3"
3437

3538

3639
[features]

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

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub struct NegotiationConfig<'a> {
2929
pub avoid_tpm: bool,
3030
pub ca_certificate: &'a str,
3131
pub client_certificate: &'a str,
32+
pub enable_authentication: bool,
33+
pub agent_id: &'a str,
3234
pub ima_log_path: Option<&'a str>,
3335
pub initial_delay_ms: u64,
3436
pub insecure: Option<bool>,
@@ -39,6 +41,8 @@ pub struct NegotiationConfig<'a> {
3941
pub uefi_log_path: Option<&'a str>,
4042
pub url: &'a str,
4143
pub verifier_url: &'a str,
44+
pub tls_accept_invalid_certs: bool,
45+
pub tls_accept_invalid_hostnames: bool,
4246
}
4347

4448
#[derive(Debug, Clone)]
@@ -59,22 +63,47 @@ impl AttestationClient {
5963
key: config.key.to_string(),
6064
insecure: config.insecure,
6165
timeout: config.timeout,
66+
accept_invalid_hostnames: config
67+
.tls_accept_invalid_hostnames,
6268
},
6369
)?)
6470
} else {
6571
None
6672
};
6773

68-
debug!("ResilientClient: initial delay: {} ms, max retries: {}, max delay: {:?} ms",
74+
debug!("ResilientClient: initial delay: {} ms, max retries: {}, max delay: {:?} ms",
6975
config.initial_delay_ms, config.max_retries, config.max_delay_ms);
70-
let client = ResilientClient::new(
76+
77+
// Create authentication config if enabled
78+
let auth_config = if config.enable_authentication {
79+
info!("Authentication ENABLED - creating auth middleware");
80+
Some(keylime::auth::AuthConfig {
81+
verifier_base_url: config.verifier_url.to_string(),
82+
agent_id: config.agent_id.to_string(),
83+
api_version: None, // Use default v3.0
84+
avoid_tpm: config.avoid_tpm,
85+
timeout_ms: keylime::config::DEFAULT_AUTH_TIMEOUT_MS,
86+
max_auth_retries: keylime::config::DEFAULT_AUTH_MAX_RETRIES,
87+
accept_invalid_certs: config.tls_accept_invalid_certs,
88+
accept_invalid_hostnames: config.tls_accept_invalid_hostnames,
89+
})
90+
} else {
91+
debug!("Authentication DISABLED - no auth middleware");
92+
None
93+
};
94+
95+
let client = ResilientClient::new_with_auth(
7196
base_client,
97+
auth_config,
7298
Duration::from_millis(config.initial_delay_ms),
7399
config.max_retries,
74100
// The success codes that stop retries
75101
&[StatusCode::OK, StatusCode::CREATED, StatusCode::ACCEPTED],
76102
config.max_delay_ms.map(Duration::from_millis),
77-
);
103+
)
104+
.map_err(|e| {
105+
anyhow::anyhow!("Failed to create resilient client: {}", e)
106+
})?;
78107

79108
Ok(AttestationClient { client })
80109
}
@@ -244,6 +273,8 @@ mod tests {
244273
avoid_tpm: true,
245274
ca_certificate: ca_path,
246275
client_certificate: cert_path,
276+
enable_authentication: false, // Disabled by default for tests
277+
agent_id: "test-agent-id",
247278
ima_log_path: None,
248279
initial_delay_ms: 0, // No initial delay in the old tests
249280
insecure: Some(false),
@@ -254,6 +285,8 @@ mod tests {
254285
uefi_log_path: None,
255286
url,
256287
verifier_url: "http://verifier.example.com",
288+
tls_accept_invalid_certs: false,
289+
tls_accept_invalid_hostnames: false,
257290
}
258291
}
259292

0 commit comments

Comments
 (0)