Skip to content

Commit 5c43ca8

Browse files
Isaac-Matthewsansasaki
authored andcommitted
Initial PR to add support for IDevID and IAK
Signed-off-by: Isaac Matthews <[email protected]>
1 parent 626a1cc commit 5c43ca8

File tree

6 files changed

+707
-20
lines changed

6 files changed

+707
-20
lines changed

keylime-agent.conf

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,21 @@ tpm_signing_alg = "rsassa"
227227
# To override ek_handle, set KEYLIME_AGENT_EK_HANDLE environment variable.
228228
ek_handle = "generate"
229229

230+
# Enable IDevID and IAK usage and set their algorithms.
231+
# Choosing a template will override the name and asymmetric algorithm choices.
232+
# Templates are specified in the TCG document found here, section 7.3.4:
233+
# https://trustedcomputinggroup.org/wp-content/uploads/TPM-2p0-Keys-for-Device-Identity-and-Attestation_v1_r12_pub10082021.pdf
234+
#
235+
# Accepted values:
236+
# iak_idevid_asymmetric_alg: rsa, ecc
237+
# iak_idevid_name_alg: sha256, sm3_256, sha384, sha512
238+
# iak_idevid_template: H-1, H-2, H-3, H-4, H-5
239+
# Leave template as "" in order to use asymmetric and name algorithm options
240+
enable_iak_idevid = false
241+
iak_idevid_asymmetric_alg = "rsa"
242+
iak_idevid_name_alg = "sha256"
243+
iak_idevid_template = ""
244+
230245
# Use this option to state the existing TPM ownerpassword.
231246
# This option should be set only when a password is set for the Endorsement
232247
# Hierarchy (e.g. via "tpm2_changeauth -c e").

keylime-agent/src/config.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ pub static DEFAULT_TPM_HASH_ALG: &str = "sha256";
5555
pub static DEFAULT_TPM_ENCRYPTION_ALG: &str = "rsa";
5656
pub static DEFAULT_TPM_SIGNING_ALG: &str = "rsassa";
5757
pub static DEFAULT_EK_HANDLE: &str = "generate";
58+
pub static DEFAULT_ENABLE_IAK_IDEVID: bool = true;
59+
pub static DEFAULT_IAK_IDEVID_ASYMMETRIC_ALG: &str = "rsa";
60+
pub static DEFAULT_IAK_IDEVID_NAME_ALG: &str = "sha256";
61+
pub static DEFAULT_IAK_IDEVID_TEMPLATE: &str = "";
5862
pub static DEFAULT_RUN_AS: &str = "keylime:tss";
5963
pub static DEFAULT_AGENT_DATA_PATH: &str = "agent_data.json";
6064
pub static DEFAULT_CONFIG: &str = "/etc/keylime/agent.conf";
@@ -94,6 +98,10 @@ pub(crate) struct EnvConfig {
9498
pub tpm_encryption_alg: Option<String>,
9599
pub tpm_signing_alg: Option<String>,
96100
pub ek_handle: Option<String>,
101+
pub enable_iak_idevid: Option<bool>,
102+
pub iak_idevid_asymmetric_alg: Option<String>,
103+
pub iak_idevid_name_alg: Option<String>,
104+
pub iak_idevid_template: Option<String>,
97105
pub run_as: Option<String>,
98106
pub agent_data_path: Option<String>,
99107
}
@@ -132,6 +140,10 @@ pub(crate) struct AgentConfig {
132140
pub tpm_encryption_alg: String,
133141
pub tpm_signing_alg: String,
134142
pub ek_handle: String,
143+
pub enable_iak_idevid: bool,
144+
pub iak_idevid_asymmetric_alg: String,
145+
pub iak_idevid_name_alg: String,
146+
pub iak_idevid_template: String,
135147
pub run_as: String,
136148
pub agent_data_path: String,
137149
}
@@ -274,6 +286,30 @@ impl EnvConfig {
274286
if let Some(ref v) = self.ek_handle {
275287
_ = agent.insert("ek_handle".to_string(), v.to_string().into());
276288
}
289+
if let Some(ref v) = self.enable_iak_idevid {
290+
_ = agent.insert(
291+
"enable_iak_idevid".to_string(),
292+
v.to_string().into(),
293+
);
294+
}
295+
if let Some(ref v) = self.iak_idevid_asymmetric_alg {
296+
_ = agent.insert(
297+
"iak_idevid_asymmetric_alg".to_string(),
298+
v.to_string().into(),
299+
);
300+
}
301+
if let Some(ref v) = self.iak_idevid_name_alg {
302+
_ = agent.insert(
303+
"iak_idevid_name_alg".to_string(),
304+
v.to_string().into(),
305+
);
306+
}
307+
if let Some(ref v) = self.iak_idevid_template {
308+
_ = agent.insert(
309+
"iak_idevid_template".to_string(),
310+
v.to_string().into(),
311+
);
312+
}
277313
if let Some(ref v) = self.run_as {
278314
_ = agent.insert("run_as".to_string(), v.to_string().into());
279315
}
@@ -438,6 +474,22 @@ impl Source for KeylimeConfig {
438474
"ek_handle".to_string(),
439475
self.agent.ek_handle.to_string().into(),
440476
);
477+
_ = m.insert(
478+
"enable_iak_idevid".to_string(),
479+
self.agent.enable_iak_idevid.into(),
480+
);
481+
_ = m.insert(
482+
"iak_idevid_asymmetric_alg".to_string(),
483+
self.agent.iak_idevid_asymmetric_alg.to_string().into(),
484+
);
485+
_ = m.insert(
486+
"iak_idevid_name_alg".to_string(),
487+
self.agent.iak_idevid_name_alg.to_string().into(),
488+
);
489+
_ = m.insert(
490+
"iak_idevid_template".to_string(),
491+
self.agent.iak_idevid_template.to_string().into(),
492+
);
441493
_ = m.insert(
442494
"run_as".to_string(),
443495
self.agent.run_as.to_string().into(),
@@ -504,6 +556,11 @@ impl Default for AgentConfig {
504556
run_as,
505557
tpm_ownerpassword: DEFAULT_TPM_OWNERPASSWORD.to_string(),
506558
ek_handle: DEFAULT_EK_HANDLE.to_string(),
559+
enable_iak_idevid: DEFAULT_ENABLE_IAK_IDEVID,
560+
iak_idevid_asymmetric_alg: DEFAULT_IAK_IDEVID_ASYMMETRIC_ALG
561+
.to_string(),
562+
iak_idevid_name_alg: DEFAULT_IAK_IDEVID_NAME_ALG.to_string(),
563+
iak_idevid_template: DEFAULT_IAK_IDEVID_TEMPLATE.to_string(),
507564
}
508565
}
509566
}
@@ -971,6 +1028,13 @@ mod tests {
9711028
("TPM_ENCRYPTION_ALG", "override_tpm_encryption_alg"),
9721029
("TPM_SIGNING_ALG", "override_tpm_signing_alg"),
9731030
("EK_HANDLE", "override_ek_handle"),
1031+
("ENABLE_IAK_IDEVID", "true"),
1032+
(
1033+
"IAK_IDEVID_ASYMMETRIC_ALG",
1034+
"override_iak_idevid_asymmetric_alg",
1035+
),
1036+
("IAK_IDEVID_NAME_ALG", "override_iak_idevid_name_alg"),
1037+
("IAK_IDEVID_TEMPLATE", "override_iak_idevid_template"),
9741038
("RUN_AS", "override_run_as"),
9751039
("AGENT_DATA_PATH", "override_agent_data_path"),
9761040
]);

keylime-agent/src/main.rs

Lines changed: 94 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ use tokio::{
7878
};
7979
use tss_esapi::{
8080
handles::KeyHandle,
81-
interface_types::algorithm::AsymmetricAlgorithm,
81+
interface_types::algorithm::{AsymmetricAlgorithm, HashingAlgorithm},
8282
interface_types::resource_handles::Hierarchy,
83-
structures::{Auth, PublicBuffer},
83+
structures::{Auth, Data, Digest, MaxBuffer, PublicBuffer},
8484
traits::Marshall,
8585
Context,
8686
};
@@ -278,6 +278,24 @@ async fn main() -> Result<()> {
278278
config.agent.tpm_signing_alg.as_ref(),
279279
)?;
280280

281+
let (asym_alg, name_alg) = tpm::get_idevid_template(
282+
config.agent.iak_idevid_template.as_str(),
283+
config.agent.iak_idevid_asymmetric_alg.as_str(),
284+
config.agent.iak_idevid_name_alg.as_str(),
285+
)?;
286+
287+
let (iak, idevid) = if config.agent.enable_iak_idevid {
288+
let idevid = ctx.create_idevid(asym_alg, name_alg)?;
289+
info!("IDevID created.");
290+
// Flush after creating to make room for AK and EK and IAK
291+
ctx.as_mut().flush_context(idevid.handle.into())?;
292+
let iak = ctx.create_iak(asym_alg, name_alg)?;
293+
info!("IAK created.");
294+
(Some(iak), Some(idevid))
295+
} else {
296+
(None, None)
297+
};
298+
281299
// Gather EK values and certs
282300
let ek_result = match config.agent.ek_handle.as_ref() {
283301
"" => ctx.create_ek(tpm_encryption_alg, None)?,
@@ -385,6 +403,26 @@ async fn main() -> Result<()> {
385403

386404
info!("Agent UUID: {}", agent_uuid);
387405

406+
let (attest, signature) = if config.agent.enable_iak_idevid {
407+
let qualifying_data = config.agent.uuid.as_bytes();
408+
let (attest, signature) = ctx.certify_credential_with_iak(
409+
Data::try_from(qualifying_data).unwrap(), //#[allow_ci]
410+
ak_handle,
411+
iak.as_ref().unwrap().handle, //#[allow_ci]
412+
)?;
413+
info!("AK certified with IAK.");
414+
415+
// // For debugging certify(), the following checks the generated signature
416+
// let max_b = MaxBuffer::try_from(attest.clone().marshall()?)?;
417+
// let (hashed_attest, _) = ctx.inner.hash(max_b, HashingAlgorithm::Sha256, Hierarchy::Endorsement,)?;
418+
// println!("{:?}", hashed_attest);
419+
// println!("{:?}", signature);
420+
// println!("{:?}", ctx.inner.verify_signature(iak.as_ref().unwrap().handle, hashed_attest, signature.clone())?); //#[allow_ci]
421+
(Some(attest), Some(signature))
422+
} else {
423+
(None, None)
424+
};
425+
388426
// Generate key pair for secure transmission of u, v keys. The u, v
389427
// keys are two halves of the key used to decrypt the workload after
390428
// the Identity and Integrity Quotes sent by the agent are validated
@@ -497,18 +535,60 @@ async fn main() -> Result<()> {
497535

498536
{
499537
// Request keyblob material
500-
let keyblob = registrar_agent::do_register_agent(
501-
config.agent.registrar_ip.as_ref(),
502-
config.agent.registrar_port,
503-
&agent_uuid,
504-
&PublicBuffer::try_from(ek_result.public.clone())?.marshall()?,
505-
ek_result.ek_cert,
506-
&PublicBuffer::try_from(ak.public)?.marshall()?,
507-
mtls_cert,
508-
config.agent.contact_ip.as_ref(),
509-
config.agent.contact_port,
510-
)
511-
.await?;
538+
let keyblob = if config.agent.enable_iak_idevid {
539+
let (Some(iak), Some(idevid), Some(attest), Some(signature)) =
540+
(iak, idevid, attest, signature)
541+
else {
542+
error!(
543+
"IDevID and IAK are enabled but could not be generated"
544+
);
545+
return Err(Error::Configuration(
546+
"IDevID and IAK are enabled but could not be generated"
547+
.to_string(),
548+
));
549+
};
550+
registrar_agent::do_register_agent(
551+
config.agent.registrar_ip.as_ref(),
552+
config.agent.registrar_port,
553+
&agent_uuid,
554+
&PublicBuffer::try_from(ek_result.public.clone())?
555+
.marshall()?,
556+
ek_result.ek_cert,
557+
&PublicBuffer::try_from(ak.public)?.marshall()?,
558+
Some(
559+
&PublicBuffer::try_from(iak.public.clone())?
560+
.marshall()?,
561+
),
562+
Some(
563+
&PublicBuffer::try_from(idevid.public.clone())?
564+
.marshall()?,
565+
),
566+
Some(attest.marshall()?),
567+
Some(signature.marshall()?),
568+
mtls_cert,
569+
config.agent.contact_ip.as_ref(),
570+
config.agent.contact_port,
571+
)
572+
.await?
573+
} else {
574+
registrar_agent::do_register_agent(
575+
config.agent.registrar_ip.as_ref(),
576+
config.agent.registrar_port,
577+
&agent_uuid,
578+
&PublicBuffer::try_from(ek_result.public.clone())?
579+
.marshall()?,
580+
ek_result.ek_cert,
581+
&PublicBuffer::try_from(ak.public)?.marshall()?,
582+
None,
583+
None,
584+
None,
585+
None,
586+
mtls_cert,
587+
config.agent.contact_ip.as_ref(),
588+
config.agent.contact_port,
589+
)
590+
.await?
591+
};
512592

513593
info!("SUCCESS: Agent {} registered", &agent_uuid);
514594

keylime-agent/src/registrar_agent.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,26 @@ struct Register<'a> {
2222
ek_tpm: &'a [u8],
2323
#[serde(serialize_with = "serialize_as_base64")]
2424
aik_tpm: &'a [u8],
25+
#[serde(
26+
serialize_with = "serialize_option_base64",
27+
skip_serializing_if = "Option::is_none"
28+
)]
29+
iak_tpm: Option<&'a [u8]>,
30+
#[serde(
31+
serialize_with = "serialize_option_base64",
32+
skip_serializing_if = "Option::is_none"
33+
)]
34+
idevid_tpm: Option<&'a [u8]>,
35+
#[serde(
36+
serialize_with = "serialize_maybe_base64",
37+
skip_serializing_if = "Option::is_none"
38+
)]
39+
iak_attest: Option<Vec<u8>>,
40+
#[serde(
41+
serialize_with = "serialize_maybe_base64",
42+
skip_serializing_if = "Option::is_none"
43+
)]
44+
iak_sign: Option<Vec<u8>>,
2545
#[serde(skip_serializing_if = "Option::is_none")]
2646
mtls_cert: Option<String>,
2747
#[serde(skip_serializing_if = "Option::is_none")]
@@ -94,6 +114,10 @@ pub(crate) async fn do_register_agent(
94114
ek_tpm: &[u8],
95115
ekcert: Option<Vec<u8>>,
96116
aik_tpm: &[u8],
117+
iak_tpm: Option<&[u8]>,
118+
idevid_tpm: Option<&[u8]>,
119+
iak_attest: Option<Vec<u8>>,
120+
iak_sign: Option<Vec<u8>>,
97121
mtls_cert_x509: Option<&X509>,
98122
ip: &str,
99123
port: u32,
@@ -113,6 +137,10 @@ pub(crate) async fn do_register_agent(
113137
ekcert,
114138
ek_tpm,
115139
aik_tpm,
140+
iak_tpm,
141+
idevid_tpm,
142+
iak_attest,
143+
iak_sign,
116144
mtls_cert,
117145
ip,
118146
port: Some(port),
@@ -195,6 +223,10 @@ mod tests {
195223
&mock_data,
196224
Some(mock_data.to_vec()),
197225
&mock_data,
226+
None,
227+
None,
228+
None,
229+
None,
198230
Some(&cert),
199231
"",
200232
0,
@@ -237,6 +269,10 @@ mod tests {
237269
&mock_data,
238270
None,
239271
&mock_data,
272+
None,
273+
None,
274+
None,
275+
None,
240276
Some(&cert),
241277
"",
242278
0,
@@ -275,6 +311,10 @@ mod tests {
275311
&mock_data,
276312
Some(mock_data.to_vec()),
277313
&mock_data,
314+
None,
315+
None,
316+
None,
317+
None,
278318
Some(&cert),
279319
"",
280320
0,

keylime-agent/src/serialization.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,21 @@ where
4848
}
4949
}
5050

51+
pub(crate) fn serialize_option_base64<S>(
52+
value: &Option<&[u8]>,
53+
serializer: S,
54+
) -> Result<S::Ok, S::Error>
55+
where
56+
S: serde::Serializer,
57+
{
58+
match *value {
59+
Some(value) => {
60+
serializer.serialize_str(&general_purpose::STANDARD.encode(value))
61+
}
62+
None => serializer.serialize_none(),
63+
}
64+
}
65+
5166
pub(crate) fn deserialize_maybe_base64<'de, D>(
5267
deserializer: D,
5368
) -> Result<Option<Vec<u8>>, D::Error>

0 commit comments

Comments
 (0)