Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial PR to add support for IDevID and IAK #608

Merged
merged 1 commit into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions keylime-agent.conf
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,21 @@ tpm_signing_alg = "rsassa"
# To override ek_handle, set KEYLIME_AGENT_EK_HANDLE environment variable.
ek_handle = "generate"

# Enable IDevID and IAK usage and set their algorithms.
# Choosing a template will override the name and asymmetric algorithm choices.
# Templates are specified in the TCG document found here, section 7.3.4:
# https://trustedcomputinggroup.org/wp-content/uploads/TPM-2p0-Keys-for-Device-Identity-and-Attestation_v1_r12_pub10082021.pdf
#
# Accepted values:
# iak_idevid_asymmetric_alg: rsa, ecc
# iak_idevid_name_alg: sha256, sm3_256, sha384, sha512
# iak_idevid_template: H-1, H-2, H-3, H-4, H-5
# Leave template as "" in order to use asymmetric and name algorithm options
enable_iak_idevid = false
iak_idevid_asymmetric_alg = "rsa"
iak_idevid_name_alg = "sha256"
ansasaki marked this conversation as resolved.
Show resolved Hide resolved
iak_idevid_template = ""

# Use this option to state the existing TPM ownerpassword.
# This option should be set only when a password is set for the Endorsement
# Hierarchy (e.g. via "tpm2_changeauth -c e").
Expand Down
64 changes: 64 additions & 0 deletions keylime-agent/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ pub static DEFAULT_TPM_HASH_ALG: &str = "sha256";
pub static DEFAULT_TPM_ENCRYPTION_ALG: &str = "rsa";
pub static DEFAULT_TPM_SIGNING_ALG: &str = "rsassa";
pub static DEFAULT_EK_HANDLE: &str = "generate";
pub static DEFAULT_ENABLE_IAK_IDEVID: bool = true;
pub static DEFAULT_IAK_IDEVID_ASYMMETRIC_ALG: &str = "rsa";
pub static DEFAULT_IAK_IDEVID_NAME_ALG: &str = "sha256";
pub static DEFAULT_IAK_IDEVID_TEMPLATE: &str = "";
pub static DEFAULT_RUN_AS: &str = "keylime:tss";
pub static DEFAULT_AGENT_DATA_PATH: &str = "agent_data.json";
pub static DEFAULT_CONFIG: &str = "/etc/keylime/agent.conf";
Expand Down Expand Up @@ -94,6 +98,10 @@ pub(crate) struct EnvConfig {
pub tpm_encryption_alg: Option<String>,
pub tpm_signing_alg: Option<String>,
pub ek_handle: Option<String>,
pub enable_iak_idevid: Option<bool>,
pub iak_idevid_asymmetric_alg: Option<String>,
pub iak_idevid_name_alg: Option<String>,
pub iak_idevid_template: Option<String>,
pub run_as: Option<String>,
pub agent_data_path: Option<String>,
}
Expand Down Expand Up @@ -132,6 +140,10 @@ pub(crate) struct AgentConfig {
pub tpm_encryption_alg: String,
pub tpm_signing_alg: String,
pub ek_handle: String,
pub enable_iak_idevid: bool,
pub iak_idevid_asymmetric_alg: String,
pub iak_idevid_name_alg: String,
pub iak_idevid_template: String,
pub run_as: String,
pub agent_data_path: String,
}
Expand Down Expand Up @@ -274,6 +286,30 @@ impl EnvConfig {
if let Some(ref v) = self.ek_handle {
_ = agent.insert("ek_handle".to_string(), v.to_string().into());
}
if let Some(ref v) = self.enable_iak_idevid {
_ = agent.insert(
"enable_iak_idevid".to_string(),
v.to_string().into(),
);
}
if let Some(ref v) = self.iak_idevid_asymmetric_alg {
_ = agent.insert(
"iak_idevid_asymmetric_alg".to_string(),
v.to_string().into(),
);
}
if let Some(ref v) = self.iak_idevid_name_alg {
_ = agent.insert(
"iak_idevid_name_alg".to_string(),
v.to_string().into(),
);
}
if let Some(ref v) = self.iak_idevid_template {
_ = agent.insert(
"iak_idevid_template".to_string(),
v.to_string().into(),
);
}
if let Some(ref v) = self.run_as {
_ = agent.insert("run_as".to_string(), v.to_string().into());
}
Expand Down Expand Up @@ -438,6 +474,22 @@ impl Source for KeylimeConfig {
"ek_handle".to_string(),
self.agent.ek_handle.to_string().into(),
);
_ = m.insert(
"enable_iak_idevid".to_string(),
self.agent.enable_iak_idevid.into(),
);
_ = m.insert(
"iak_idevid_asymmetric_alg".to_string(),
self.agent.iak_idevid_asymmetric_alg.to_string().into(),
);
_ = m.insert(
"iak_idevid_name_alg".to_string(),
self.agent.iak_idevid_name_alg.to_string().into(),
);
_ = m.insert(
"iak_idevid_template".to_string(),
self.agent.iak_idevid_template.to_string().into(),
);
_ = m.insert(
"run_as".to_string(),
self.agent.run_as.to_string().into(),
Expand Down Expand Up @@ -504,6 +556,11 @@ impl Default for AgentConfig {
run_as,
tpm_ownerpassword: DEFAULT_TPM_OWNERPASSWORD.to_string(),
ek_handle: DEFAULT_EK_HANDLE.to_string(),
enable_iak_idevid: DEFAULT_ENABLE_IAK_IDEVID,
iak_idevid_asymmetric_alg: DEFAULT_IAK_IDEVID_ASYMMETRIC_ALG
.to_string(),
iak_idevid_name_alg: DEFAULT_IAK_IDEVID_NAME_ALG.to_string(),
iak_idevid_template: DEFAULT_IAK_IDEVID_TEMPLATE.to_string(),
}
}
}
Expand Down Expand Up @@ -971,6 +1028,13 @@ mod tests {
("TPM_ENCRYPTION_ALG", "override_tpm_encryption_alg"),
("TPM_SIGNING_ALG", "override_tpm_signing_alg"),
("EK_HANDLE", "override_ek_handle"),
("ENABLE_IAK_IDEVID", "true"),
(
"IAK_IDEVID_ASYMMETRIC_ALG",
"override_iak_idevid_asymmetric_alg",
),
("IAK_IDEVID_NAME_ALG", "override_iak_idevid_name_alg"),
("IAK_IDEVID_TEMPLATE", "override_iak_idevid_template"),
("RUN_AS", "override_run_as"),
("AGENT_DATA_PATH", "override_agent_data_path"),
]);
Expand Down
108 changes: 94 additions & 14 deletions keylime-agent/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ use tokio::{
};
use tss_esapi::{
handles::KeyHandle,
interface_types::algorithm::AsymmetricAlgorithm,
interface_types::algorithm::{AsymmetricAlgorithm, HashingAlgorithm},
interface_types::resource_handles::Hierarchy,
structures::{Auth, PublicBuffer},
structures::{Auth, Data, Digest, MaxBuffer, PublicBuffer},
traits::Marshall,
Context,
};
Expand Down Expand Up @@ -278,6 +278,24 @@ async fn main() -> Result<()> {
config.agent.tpm_signing_alg.as_ref(),
)?;

let (asym_alg, name_alg) = tpm::get_idevid_template(
config.agent.iak_idevid_template.as_str(),
config.agent.iak_idevid_asymmetric_alg.as_str(),
config.agent.iak_idevid_name_alg.as_str(),
)?;

let (iak, idevid) = if config.agent.enable_iak_idevid {
let idevid = ctx.create_idevid(asym_alg, name_alg)?;
info!("IDevID created.");
// Flush after creating to make room for AK and EK and IAK
ctx.as_mut().flush_context(idevid.handle.into())?;
let iak = ctx.create_iak(asym_alg, name_alg)?;
info!("IAK created.");
(Some(iak), Some(idevid))
} else {
(None, None)
};

// Gather EK values and certs
let ek_result = match config.agent.ek_handle.as_ref() {
"" => ctx.create_ek(tpm_encryption_alg, None)?,
Expand Down Expand Up @@ -385,6 +403,26 @@ async fn main() -> Result<()> {

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

let (attest, signature) = if config.agent.enable_iak_idevid {
let qualifying_data = config.agent.uuid.as_bytes();
let (attest, signature) = ctx.certify_credential_with_iak(
Data::try_from(qualifying_data).unwrap(), //#[allow_ci]
ak_handle,
iak.as_ref().unwrap().handle, //#[allow_ci]
)?;
info!("AK certified with IAK.");

// // For debugging certify(), the following checks the generated signature
// let max_b = MaxBuffer::try_from(attest.clone().marshall()?)?;
// let (hashed_attest, _) = ctx.inner.hash(max_b, HashingAlgorithm::Sha256, Hierarchy::Endorsement,)?;
// println!("{:?}", hashed_attest);
// println!("{:?}", signature);
// println!("{:?}", ctx.inner.verify_signature(iak.as_ref().unwrap().handle, hashed_attest, signature.clone())?); //#[allow_ci]
(Some(attest), Some(signature))
} else {
(None, None)
};

// Generate key pair for secure transmission of u, v keys. The u, v
// keys are two halves of the key used to decrypt the workload after
// the Identity and Integrity Quotes sent by the agent are validated
Expand Down Expand Up @@ -497,18 +535,60 @@ async fn main() -> Result<()> {

{
// Request keyblob material
let keyblob = registrar_agent::do_register_agent(
config.agent.registrar_ip.as_ref(),
config.agent.registrar_port,
&agent_uuid,
&PublicBuffer::try_from(ek_result.public.clone())?.marshall()?,
ek_result.ek_cert,
&PublicBuffer::try_from(ak.public)?.marshall()?,
mtls_cert,
config.agent.contact_ip.as_ref(),
config.agent.contact_port,
)
.await?;
let keyblob = if config.agent.enable_iak_idevid {
let (Some(iak), Some(idevid), Some(attest), Some(signature)) =
(iak, idevid, attest, signature)
else {
error!(
"IDevID and IAK are enabled but could not be generated"
);
return Err(Error::Configuration(
"IDevID and IAK are enabled but could not be generated"
.to_string(),
));
};
registrar_agent::do_register_agent(
config.agent.registrar_ip.as_ref(),
config.agent.registrar_port,
&agent_uuid,
&PublicBuffer::try_from(ek_result.public.clone())?
.marshall()?,
ek_result.ek_cert,
&PublicBuffer::try_from(ak.public)?.marshall()?,
Some(
&PublicBuffer::try_from(iak.public.clone())?
.marshall()?,
),
Some(
&PublicBuffer::try_from(idevid.public.clone())?
.marshall()?,
),
Some(attest.marshall()?),
Some(signature.marshall()?),
mtls_cert,
config.agent.contact_ip.as_ref(),
config.agent.contact_port,
)
.await?
} else {
registrar_agent::do_register_agent(
config.agent.registrar_ip.as_ref(),
config.agent.registrar_port,
&agent_uuid,
&PublicBuffer::try_from(ek_result.public.clone())?
.marshall()?,
ek_result.ek_cert,
&PublicBuffer::try_from(ak.public)?.marshall()?,
None,
None,
None,
None,
mtls_cert,
config.agent.contact_ip.as_ref(),
config.agent.contact_port,
)
.await?
};

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

Expand Down
40 changes: 40 additions & 0 deletions keylime-agent/src/registrar_agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,26 @@ struct Register<'a> {
ek_tpm: &'a [u8],
#[serde(serialize_with = "serialize_as_base64")]
aik_tpm: &'a [u8],
#[serde(
serialize_with = "serialize_option_base64",
skip_serializing_if = "Option::is_none"
)]
iak_tpm: Option<&'a [u8]>,
#[serde(
serialize_with = "serialize_option_base64",
skip_serializing_if = "Option::is_none"
)]
idevid_tpm: Option<&'a [u8]>,
#[serde(
serialize_with = "serialize_maybe_base64",
skip_serializing_if = "Option::is_none"
)]
iak_attest: Option<Vec<u8>>,
#[serde(
serialize_with = "serialize_maybe_base64",
skip_serializing_if = "Option::is_none"
)]
iak_sign: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Option::is_none")]
mtls_cert: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
Expand Down Expand Up @@ -94,6 +114,10 @@ pub(crate) async fn do_register_agent(
ek_tpm: &[u8],
ekcert: Option<Vec<u8>>,
aik_tpm: &[u8],
iak_tpm: Option<&[u8]>,
idevid_tpm: Option<&[u8]>,
iak_attest: Option<Vec<u8>>,
iak_sign: Option<Vec<u8>>,
mtls_cert_x509: Option<&X509>,
ip: &str,
port: u32,
Expand All @@ -113,6 +137,10 @@ pub(crate) async fn do_register_agent(
ekcert,
ek_tpm,
aik_tpm,
iak_tpm,
idevid_tpm,
iak_attest,
iak_sign,
mtls_cert,
ip,
port: Some(port),
Expand Down Expand Up @@ -195,6 +223,10 @@ mod tests {
&mock_data,
Some(mock_data.to_vec()),
&mock_data,
None,
None,
None,
None,
Some(&cert),
"",
0,
Expand Down Expand Up @@ -237,6 +269,10 @@ mod tests {
&mock_data,
None,
&mock_data,
None,
None,
None,
None,
Some(&cert),
"",
0,
Expand Down Expand Up @@ -275,6 +311,10 @@ mod tests {
&mock_data,
Some(mock_data.to_vec()),
&mock_data,
None,
None,
None,
None,
Some(&cert),
"",
0,
Expand Down
15 changes: 15 additions & 0 deletions keylime-agent/src/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ where
}
}

pub(crate) fn serialize_option_base64<S>(
value: &Option<&[u8]>,
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match *value {
Some(value) => {
serializer.serialize_str(&general_purpose::STANDARD.encode(value))
}
None => serializer.serialize_none(),
}
}

pub(crate) fn deserialize_maybe_base64<'de, D>(
deserializer: D,
) -> Result<Option<Vec<u8>>, D::Error>
Expand Down
Loading
Loading