Skip to content

Commit 2091359

Browse files
committed
Use separate keys for payload mechanism and mTLS
This allows algorithms other than RSA to be used for mTLS. The payload encryption mechanism requires an RSA key pair, so always generate an RSA key for the payload mechanism. This renames the 'nk_pub' and 'nk_priv' respectively as 'mtls_pub' and 'mtls_priv' when they are used for mTLS. Signed-off-by: Anderson Toshiyuki Sasaki <[email protected]>
1 parent ef83ed2 commit 2091359

File tree

4 files changed

+50
-37
lines changed

4 files changed

+50
-37
lines changed

keylime-agent/src/keys_handler.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ async fn u_key(
166166
// https://github.com/keylime/keylime/blob/f3c31b411dd3dd971fd9d614a39a150655c6797c/ \
167167
// keylime/crypto.py#L118
168168
let decrypted_key = match crypto::rsa_oaep_decrypt(
169-
&quote_data.priv_key,
169+
&quote_data.payload_priv_key,
170170
&encrypted_key,
171171
)
172172
.map_err(Error::from)
@@ -278,7 +278,7 @@ async fn v_key(
278278
// https://github.com/keylime/keylime/blob/f3c31b411dd3dd971fd9d614a39a150655c6797c/ \
279279
// keylime/crypto.py#L118
280280
let decrypted_key = match crypto::rsa_oaep_decrypt(
281-
&quote_data.priv_key,
281+
&quote_data.payload_priv_key,
282282
&encrypted_key,
283283
)
284284
.map_err(Error::from)
@@ -323,7 +323,7 @@ async fn pubkey(
323323
req: HttpRequest,
324324
data: web::Data<QuoteData<'_>>,
325325
) -> impl Responder {
326-
match crypto::pkey_pub_to_pem(&data.pub_key) {
326+
match crypto::pkey_pub_to_pem(&data.payload_pub_key) {
327327
Ok(pubkey) => {
328328
let response = JsonWrapper::success(KeylimePubkey { pubkey });
329329
info!("GET pubkey returning 200 response.");
@@ -902,7 +902,7 @@ mod tests {
902902
fixture.keys_tx = keys_tx.clone();
903903

904904
let quotedata = web::Data::new(fixture);
905-
let pubkey = quotedata.pub_key.clone();
905+
let pubkey = quotedata.payload_pub_key.clone();
906906

907907
// Run server
908908
let mut app = test::init_service(
@@ -968,7 +968,7 @@ mod tests {
968968
})));
969969

970970
let encrypted_key =
971-
rsa_oaep_encrypt(&quotedata.pub_key, u.as_ref()).unwrap(); //#[allow_ci]
971+
rsa_oaep_encrypt(&quotedata.payload_pub_key, u.as_ref()).unwrap(); //#[allow_ci]
972972

973973
let ukey = KeylimeUKey {
974974
encrypted_key: general_purpose::STANDARD.encode(&encrypted_key),
@@ -985,7 +985,7 @@ mod tests {
985985
assert!(resp.status().is_success());
986986

987987
let encrypted_key =
988-
rsa_oaep_encrypt(&quotedata.pub_key, v.as_ref()).unwrap(); //#[allow_ci]
988+
rsa_oaep_encrypt(&quotedata.payload_pub_key, v.as_ref()).unwrap(); //#[allow_ci]
989989

990990
let vkey = KeylimeVKey {
991991
encrypted_key: general_purpose::STANDARD.encode(&encrypted_key),
@@ -1110,7 +1110,7 @@ mod tests {
11101110
test::read_body_json(resp).await;
11111111
assert!(pkey_pub_from_pem(&result.results.pubkey)
11121112
.unwrap() //#[allow_ci]
1113-
.public_eq(&quotedata.pub_key));
1113+
.public_eq(&quotedata.payload_pub_key));
11141114

11151115
// Explicitly drop QuoteData to cleanup keys
11161116
drop(quotedata);

keylime-agent/src/main.rs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ pub struct QuoteData<'a> {
114114
)>,
115115
measuredboot_ml_file: Option<Mutex<fs::File>>,
116116
payload_tx: mpsc::Sender<payloads::PayloadMessage>,
117+
payload_priv_key: PKey<Private>,
118+
payload_pub_key: PKey<Public>,
117119
priv_key: PKey<Private>,
118120
pub_key: PKey<Public>,
119121
revocation_tx: mpsc::Sender<revocation::RevocationMessage>,
@@ -488,35 +490,36 @@ async fn main() -> Result<()> {
488490
(None, None)
489491
};
490492

491-
// Generate key pair for secure transmission of u, v keys. The u, v
492-
// keys are two halves of the key used to decrypt the workload after
493+
// Generate ephemeral RSA key pair for secure transmission of u, v keys.
494+
// The u, v keys are two halves of the key used to decrypt the workload after
493495
// the Identity and Integrity Quotes sent by the agent are validated
494496
// by the Tenant and Cloud Verifier, respectively.
495-
//
496-
// Since we store the u key in memory, discarding this key, which
497-
// safeguards u and v keys in transit, is not part of the threat model.
497+
debug!("Generating ephemeral RSA key pair for payload mechanism");
498+
let (payload_pub_key, payload_priv_key) =
499+
crypto::rsa_generate_pair(2048)?;
498500

499-
let (nk_pub, nk_priv) = match config.server_key.as_ref() {
501+
// Generate mTLS key pair (separate from payload keys)
502+
let (mtls_pub, mtls_priv) = match config.server_key.as_ref() {
500503
"" => {
501504
debug!(
502505
"The server_key option was not set in the configuration file"
503506
);
504-
debug!("Generating new key pair");
507+
debug!("Generating new mTLS key pair");
505508
crypto::rsa_generate_pair(2048)?
506509
}
507510
path => {
508511
let key_path = Path::new(&path);
509512
if key_path.exists() {
510513
debug!(
511-
"Loading existing key pair from {}",
514+
"Loading existing mTLS key pair from {}",
512515
key_path.display()
513516
);
514517
crypto::load_key_pair(
515518
key_path,
516519
Some(config.server_key_password.as_ref()),
517520
)?
518521
} else {
519-
debug!("Generating new key pair");
522+
debug!("Generating new mTLS key pair");
520523
let (public, private) = crypto::rsa_generate_pair(2048)?;
521524
// Write the generated key to the file
522525
crypto::write_key_pair(
@@ -539,7 +542,7 @@ async fn main() -> Result<()> {
539542
debug!("The server_cert option was not set in the configuration file");
540543

541544
crypto::x509::CertificateBuilder::new()
542-
.private_key(&nk_priv)
545+
.private_key(&mtls_priv)
543546
.common_name(&agent_uuid)
544547
.add_ips(contact_ips)
545548
.build()?
@@ -555,7 +558,7 @@ async fn main() -> Result<()> {
555558
} else {
556559
debug!("Generating new mTLS certificate");
557560
let cert = crypto::x509::CertificateBuilder::new()
558-
.private_key(&nk_priv)
561+
.private_key(&mtls_priv)
559562
.common_name(&agent_uuid)
560563
.add_ips(contact_ips)
561564
.build()?;
@@ -598,7 +601,7 @@ async fn main() -> Result<()> {
598601
mtls_cert = Some(cert.clone());
599602
ssl_context = Some(crypto::generate_tls_context(
600603
&cert,
601-
&nk_priv,
604+
&mtls_priv,
602605
keylime_ca_certs,
603606
)?);
604607
} else {
@@ -694,8 +697,10 @@ async fn main() -> Result<()> {
694697
keys_tx: keys_tx.clone(),
695698
measuredboot_ml_file,
696699
payload_tx: payload_tx.clone(),
697-
priv_key: nk_priv,
698-
pub_key: nk_pub,
700+
payload_priv_key,
701+
payload_pub_key,
702+
priv_key: mtls_priv,
703+
pub_key: mtls_pub,
699704
revocation_tx: revocation_tx.clone(),
700705
secure_mount: PathBuf::from(&mount),
701706
secure_size,
@@ -992,8 +997,13 @@ mod testing {
992997
.join("test-data")
993998
.join("test-rsa.pem");
994999

995-
let (nk_pub, nk_priv) =
996-
crypto::testing::rsa_import_pair(rsa_key_path)?;
1000+
let (mtls_pub, mtls_priv) =
1001+
crypto::testing::rsa_import_pair(rsa_key_path.clone())?;
1002+
1003+
// Generate separate ephemeral payload keys for testing
1004+
debug!("Generating ephemeral RSA key pair for payload mechanism");
1005+
let (payload_pub_key, payload_priv_key) =
1006+
crypto::rsa_generate_pair(2048)?;
9971007

9981008
let (mut payload_tx, mut payload_rx) =
9991009
mpsc::channel::<payloads::PayloadMessage>(1);
@@ -1046,8 +1056,10 @@ mod testing {
10461056
QuoteData {
10471057
api_versions,
10481058
tpmcontext: Mutex::new(ctx),
1049-
priv_key: nk_priv,
1050-
pub_key: nk_pub,
1059+
payload_priv_key,
1060+
payload_pub_key,
1061+
priv_key: mtls_priv,
1062+
pub_key: mtls_pub,
10511063
ak_handle,
10521064
keys_tx,
10531065
payload_tx,

keylime-agent/src/quotes_handler.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub struct Ident {
2525

2626
// This is a Quote request from the tenant, which does not check
2727
// integrity measurement. It should return this data:
28-
// { QuoteAIK(nonce, 16:H(NK_pub)), NK_pub }
28+
// { QuoteAIK(nonce, 16:H(payload_pub)), payload_pub }
2929
async fn identity(
3030
req: HttpRequest,
3131
param: web::Query<Ident>,
@@ -67,7 +67,7 @@ async fn identity(
6767
let tpm_quote = match context.quote(
6868
param.nonce.as_bytes(),
6969
0,
70-
&data.pub_key,
70+
&data.payload_pub_key,
7171
data.ak_handle,
7272
data.hash_alg,
7373
data.sign_alg,
@@ -92,7 +92,7 @@ async fn identity(
9292
..Default::default()
9393
};
9494

95-
match crypto::pkey_pub_to_pem(&data.pub_key) {
95+
match crypto::pkey_pub_to_pem(&data.payload_pub_key) {
9696
Ok(pubkey) => quote.pubkey = Some(pubkey),
9797
Err(e) => {
9898
debug!("Unable to retrieve public key for quote: {e:?}");
@@ -113,7 +113,7 @@ async fn identity(
113113
// This is a Quote request from the cloud verifier, which will check
114114
// integrity measurement. The PCRs included in the Quote will be specified
115115
// by the mask. It should return this data:
116-
// { QuoteAIK(nonce, 16:H(NK_pub), xi:yi), NK_pub}
116+
// { QuoteAIK(nonce, 16:H(payload_pub), xi:yi), payload_pub}
117117
// where xi:yi are additional PCRs to be included in the quote.
118118
async fn integrity(
119119
req: HttpRequest,
@@ -169,7 +169,8 @@ async fn integrity(
169169
// If partial="0", include the public key in the quote
170170
let pubkey = match &param.partial[..] {
171171
"0" => {
172-
let pubkey = match crypto::pkey_pub_to_pem(&data.pub_key) {
172+
let pubkey = match crypto::pkey_pub_to_pem(&data.payload_pub_key)
173+
{
173174
Ok(pubkey) => pubkey,
174175
Err(e) => {
175176
debug!("Unable to retrieve public key: {e:?}");
@@ -214,7 +215,7 @@ async fn integrity(
214215
let tpm_quote = match context.quote(
215216
param.nonce.as_bytes(),
216217
mask,
217-
&data.pub_key,
218+
&data.payload_pub_key,
218219
data.ak_handle,
219220
data.hash_alg,
220221
data.sign_alg,
@@ -389,7 +390,7 @@ mod tests {
389390
assert!(
390391
pkey_pub_from_pem(&result.results.pubkey.unwrap()) //#[allow_ci]
391392
.unwrap() //#[allow_ci]
392-
.public_eq(&quotedata.pub_key)
393+
.public_eq(&quotedata.payload_pub_key)
393394
);
394395
assert!(result.results.quote.starts_with('r'));
395396

@@ -435,7 +436,7 @@ mod tests {
435436
assert!(
436437
pkey_pub_from_pem(&result.results.pubkey.unwrap()) //#[allow_ci]
437438
.unwrap() //#[allow_ci]
438-
.public_eq(&quotedata.pub_key)
439+
.public_eq(&quotedata.payload_pub_key)
439440
);
440441

441442
if let Some(ima_mutex) = &quotedata.ima_ml_file {

keylime/src/cert.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub fn cert_from_server_key(
1717
config: &CertificateConfig,
1818
) -> Result<(X509, PKey<Public>)> {
1919
let cert: X509;
20-
let (nk_pub, nk_priv) = match config.server_key.as_ref() {
20+
let (mtls_pub, mtls_priv) = match config.server_key.as_ref() {
2121
"" => {
2222
debug!(
2323
"The server_key option was not set in the configuration file"
@@ -56,7 +56,7 @@ pub fn cert_from_server_key(
5656
debug!("The server_cert option was not set in the configuration file");
5757

5858
crypto::x509::CertificateBuilder::new()
59-
.private_key(&nk_priv)
59+
.private_key(&mtls_priv)
6060
.common_name(&config.agent_uuid)
6161
.add_ips(contact_ips)
6262
.build()?
@@ -72,7 +72,7 @@ pub fn cert_from_server_key(
7272
} else {
7373
debug!("Generating new mTLS certificate");
7474
let cert = crypto::x509::CertificateBuilder::new()
75-
.private_key(&nk_priv)
75+
.private_key(&mtls_priv)
7676
.common_name(&config.agent_uuid)
7777
.add_ips(contact_ips)
7878
.build()?;
@@ -81,7 +81,7 @@ pub fn cert_from_server_key(
8181
}
8282
}
8383
};
84-
Ok((cert, nk_pub))
84+
Ok((cert, mtls_pub))
8585
}
8686

8787
#[cfg(test)]

0 commit comments

Comments
 (0)