Skip to content

Commit bec5d94

Browse files
committed
Persist payload keys to avoid attestation failure on restart
Previously, when the agent was restarted while being monitored by the verifier, it would fail attestation because the PCR#16 would be extended with the new ephemeral payload public key. With this change, the payload key is persisted, making the agent to reuse the previously generated payload key instead of generating a new ephemeral key on restart. Resolves: #1136 Signed-off-by: Anderson Toshiyuki Sasaki <[email protected]>
1 parent ab3901f commit bec5d94

File tree

5 files changed

+74
-39
lines changed

5 files changed

+74
-39
lines changed

keylime-agent.conf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,28 @@ server_key = "default"
8787
# environment variable.
8888
server_key_password = ""
8989

90+
# The name of the file containing the payload encryption private key.
91+
# This private key is used to decrypt U and V keys sent by the verifier/tenant
92+
# for secure payload transmission.
93+
# A new RSA 2048 private key is generated in case it is not found.
94+
# If an existing key is provided, it MUST be RSA 2048, otherwise the agent will
95+
# fail to start.
96+
# If set as "default", the "payload-private.pem" value is used.
97+
# If a relative path is set, it will be considered relative from the keylime_dir.
98+
# If an absolute path is set, it is used without change.
99+
#
100+
# To override payload_key, set KEYLIME_AGENT_PAYLOAD_KEY environment variable.
101+
payload_key = "default"
102+
103+
# Set the password used to encrypt the payload private key file.
104+
# This password will also be used to protect the generated private key used for
105+
# payload encryption.
106+
# If left empty, the private key will not be encrypted.
107+
#
108+
# To override payload_key_password, set KEYLIME_AGENT_PAYLOAD_KEY_PASSWORD
109+
# environment variable.
110+
payload_key_password = ""
111+
90112
# The name of the file containing the X509 certificate used as the Keylime agent
91113
# server TLS certificate.
92114
# This certificate must be self signed.

keylime-agent/src/main.rs

Lines changed: 30 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -490,47 +490,38 @@ async fn main() -> Result<()> {
490490
(None, None)
491491
};
492492

493-
// Generate ephemeral RSA key pair for secure transmission of u, v keys.
493+
// Load or generate RSA key pair for secure transmission of u, v keys.
494494
// The u, v keys are two halves of the key used to decrypt the workload after
495495
// the Identity and Integrity Quotes sent by the agent are validated
496496
// by the Tenant and Cloud Verifier, respectively.
497-
debug!("Generating ephemeral RSA key pair for payload mechanism");
498-
let (payload_pub_key, payload_priv_key) =
499-
crypto::rsa_generate_pair(2048)?;
500-
501-
// Generate mTLS key pair (separate from payload keys)
502-
let (mtls_pub, mtls_priv) = match config.server_key.as_ref() {
503-
"" => {
504-
debug!(
505-
"The server_key option was not set in the configuration file"
506-
);
507-
debug!("Generating new mTLS key pair");
508-
crypto::rsa_generate_pair(2048)?
509-
}
510-
path => {
511-
let key_path = Path::new(&path);
512-
if key_path.exists() {
513-
debug!(
514-
"Loading existing mTLS key pair from {}",
515-
key_path.display()
516-
);
517-
crypto::load_key_pair(
518-
key_path,
519-
Some(config.server_key_password.as_ref()),
520-
)?
521-
} else {
522-
debug!("Generating new mTLS key pair");
523-
let (public, private) = crypto::rsa_generate_pair(2048)?;
524-
// Write the generated key to the file
525-
crypto::write_key_pair(
526-
&private,
527-
key_path,
528-
Some(config.server_key_password.as_ref()),
529-
);
530-
(public, private)
531-
}
532-
}
533-
};
497+
// The payload key is always persistent, stored at the configured path.
498+
let key_path = Path::new(&config.payload_key);
499+
let (payload_pub_key, payload_priv_key) = crypto::load_or_generate_key(
500+
key_path,
501+
Some(config.payload_key_password.as_ref()),
502+
keylime::algorithms::EncryptionAlgorithm::Rsa2048,
503+
true, // Validate that loaded keys are RSA 2048
504+
)
505+
.map_err(|e| {
506+
error!(
507+
"Failed to load or generate payload key from {}: {e}",
508+
key_path.display()
509+
);
510+
Error::Configuration(config::KeylimeConfigError::Generic(format!(
511+
"Failed to load or generate payload key from {}: {e}",
512+
key_path.display()
513+
)))
514+
})?;
515+
516+
// Load or generate mTLS key pair (separate from payload keys)
517+
// The mTLS key is always persistent, stored at the configured path.
518+
let key_path = Path::new(&config.server_key);
519+
let (mtls_pub, mtls_priv) = crypto::load_or_generate_key(
520+
key_path,
521+
Some(config.server_key_password.as_ref()),
522+
keylime::algorithms::EncryptionAlgorithm::Rsa2048,
523+
false, // Don't validate algorithm for mTLS keys (for backward compatibility)
524+
)?;
534525

535526
let cert: X509;
536527
let mtls_cert;
@@ -1000,7 +991,7 @@ mod testing {
1000991
let (mtls_pub, mtls_priv) =
1001992
crypto::testing::rsa_import_pair(rsa_key_path.clone())?;
1002993

1003-
// Generate separate ephemeral payload keys for testing
994+
// Generate ephemeral payload keys for testing
1004995
debug!("Generating ephemeral RSA key pair for payload mechanism");
1005996
let (payload_pub_key, payload_priv_key) =
1006997
crypto::rsa_generate_pair(2048)?;

keylime/src/config/base.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ pub static DEFAULT_SECURE_SIZE: &str = "1m";
8080
pub static DEFAULT_SERVER_CERT: &str = "server-cert.crt";
8181
pub static DEFAULT_SERVER_KEY: &str = "server-private.pem";
8282
pub static DEFAULT_SERVER_KEY_PASSWORD: &str = "";
83+
pub static DEFAULT_PAYLOAD_KEY: &str = "payload-private.pem";
84+
pub static DEFAULT_PAYLOAD_KEY_PASSWORD: &str = "";
8385
// The DEFAULT_TRUSTED_CLIENT_CA is relative from KEYLIME_DIR
8486
pub static DEFAULT_TRUSTED_CLIENT_CA: &str = "cv_ca/cacert.crt";
8587

@@ -157,6 +159,8 @@ pub struct AgentConfig {
157159
pub server_cert: String,
158160
pub server_key: String,
159161
pub server_key_password: String,
162+
pub payload_key: String,
163+
pub payload_key_password: String,
160164

161165
// Push attestation options
162166
pub certification_keys_server_identifier: String,
@@ -307,6 +311,8 @@ impl Default for AgentConfig {
307311
server_cert: "default".to_string(),
308312
server_key: "default".to_string(),
309313
server_key_password: DEFAULT_SERVER_KEY_PASSWORD.to_string(),
314+
payload_key: "default".to_string(),
315+
payload_key_password: DEFAULT_PAYLOAD_KEY_PASSWORD.to_string(),
310316
tpm_encryption_alg: DEFAULT_TPM_ENCRYPTION_ALG.to_string(),
311317
tpm_hash_alg: DEFAULT_TPM_HASH_ALG.to_string(),
312318
tpm_ownerpassword: DEFAULT_TPM_OWNERPASSWORD.to_string(),
@@ -415,6 +421,14 @@ pub(crate) fn config_translate_keywords(
415421
false,
416422
);
417423

424+
let payload_key = config_get_file_path(
425+
"payload_key",
426+
&config.payload_key,
427+
keylime_dir,
428+
DEFAULT_PAYLOAD_KEY,
429+
false,
430+
);
431+
418432
let trusted_client_ca: String = parse_list(&config.trusted_client_ca)?
419433
.iter()
420434
.map(|t| {
@@ -612,6 +626,7 @@ pub(crate) fn config_translate_keywords(
612626
revocation_cert,
613627
server_cert,
614628
server_key,
629+
payload_key,
615630
trusted_client_ca,
616631
uuid,
617632
..config.clone()

keylime/src/config/env.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ mod test {
145145
"KEYLIME_AGENT_SERVER_KEY_PASSWORD",
146146
"override_server_key_password",
147147
),
148+
("KEYLIME_AGENT_PAYLOAD_KEY", "override_payload_key"),
149+
(
150+
"KEYLIME_AGENT_PAYLOAD_KEY_PASSWORD",
151+
"override_payload_key_password",
152+
),
148153
(
149154
"KEYLIME_AGENT_TPM_ENCRYPTION_ALG",
150155
"override_tpm_encryption_alg",

keylime/src/config/testing.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ fn apply_config_overrides(
150150
"server_cert" => config.server_cert = value,
151151
"server_key" => config.server_key = value,
152152
"server_key_password" => config.server_key_password = value,
153+
"payload_key" => config.payload_key = value,
154+
"payload_key_password" => config.payload_key_password = value,
153155
// Push attestation options
154156
"certification_keys_server_identifier" => {
155157
config.certification_keys_server_identifier = value

0 commit comments

Comments
 (0)