Skip to content

Commit 78e19f1

Browse files
committed
main: Move IAK/IDevID related code to dedicated module
Move the IAK/IDevID initialization code to the dedicated module 'device_id'. The module implements the builder pattern to set the parameters set through configuration. The goal is to simplify the code in main. Signed-off-by: Anderson Toshiyuki Sasaki <[email protected]>
1 parent 2a91d66 commit 78e19f1

File tree

6 files changed

+591
-163
lines changed

6 files changed

+591
-163
lines changed

keylime-agent/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ pub(crate) enum Error {
2727
Conversion(String),
2828
#[error("Configuration error")]
2929
Configuration(#[from] crate::config::KeylimeConfigError),
30+
#[error("Device ID error")]
31+
DeviceID(#[from] keylime::device_id::DeviceIDError),
32+
#[error("Device ID builder error")]
33+
DeviceIDBuilder(#[from] keylime::device_id::DeviceIDBuilderError),
3034
#[error("Reqwest error: {0}")]
3135
Reqwest(#[from] reqwest::Error),
3236
#[error("Registrar error: received {code} from {addr}")]

keylime-agent/src/main.rs

Lines changed: 38 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ use futures::{
5858
try_join,
5959
};
6060
use keylime::{
61-
crypto, crypto::x509::CertificateBuilder, ima::MeasurementList,
62-
list_parser::parse_list, tpm,
61+
crypto::{self, x509::CertificateBuilder},
62+
device_id::{DeviceID, DeviceIDBuilder},
63+
ima::MeasurementList,
64+
list_parser::parse_list,
65+
tpm::{self, IAKResult, IDevIDResult},
6366
};
6467
use log::*;
6568
use openssl::{
@@ -324,137 +327,6 @@ async fn main() -> Result<()> {
324327
config.agent.tpm_signing_alg.as_ref(),
325328
)?;
326329

327-
let iak_cert: Option<X509>;
328-
let idevid_cert: Option<X509>;
329-
// Attempt to load the IAK and IDevID certificates
330-
if config.agent.enable_iak_idevid {
331-
iak_cert = match config.agent.iak_cert.as_ref() {
332-
"" => {
333-
debug!("The iak_cert option was not set in the configuration file");
334-
None
335-
}
336-
path => {
337-
let iak_path = Path::new(&path);
338-
if iak_path.exists() {
339-
debug!(
340-
"Loading IAK certificate from {}",
341-
iak_path.display()
342-
);
343-
let iakcert = match crypto::load_x509_der(iak_path) {
344-
Ok(cert) => cert,
345-
Err(error) => crypto::load_x509_pem(iak_path)?,
346-
};
347-
Some(iakcert)
348-
} else {
349-
debug!("Can not find IAK certificate");
350-
None
351-
}
352-
}
353-
};
354-
idevid_cert = match config.agent.idevid_cert.as_ref() {
355-
"" => {
356-
debug!("The idevid_cert option was not set in the configuration file");
357-
None
358-
}
359-
path => {
360-
let idevid_path = Path::new(&path);
361-
if idevid_path.exists() {
362-
debug!(
363-
"Loading IDevID certificate from {}",
364-
idevid_path.display()
365-
);
366-
let idevcert = match crypto::load_x509_der(idevid_path) {
367-
Ok(cert) => cert,
368-
Err(error) => crypto::load_x509_pem(idevid_path)?,
369-
};
370-
Some(idevcert)
371-
} else {
372-
debug!("Can not find IDevID certificate");
373-
None
374-
}
375-
}
376-
};
377-
} else {
378-
iak_cert = None;
379-
idevid_cert = None;
380-
}
381-
/// Regenerate the IAK and IDevID keys or collect and authorise persisted ones and check that the keys match the certificates that have been loaded
382-
let (iak, idevid) = if config.agent.enable_iak_idevid {
383-
/// Try to detect which template has been used by checking the certificate
384-
let (asym_alg, name_alg) = tpm::get_idevid_template(
385-
&crypto::match_cert_to_template(
386-
&iak_cert.clone().ok_or(Error::Other(
387-
"IAK/IDevID enabled but cert could not be used"
388-
.to_string(),
389-
))?,
390-
)?,
391-
config.agent.iak_idevid_template.as_str(),
392-
config.agent.iak_idevid_asymmetric_alg.as_str(),
393-
config.agent.iak_idevid_name_alg.as_str(),
394-
)?;
395-
396-
/// IDevID recreation/collection
397-
let idevid = if config.agent.idevid_handle.trim().is_empty() {
398-
/// If handle is not set in config, recreate IDevID according to template
399-
info!("Recreating IDevID.");
400-
let regen_idev = ctx.create_idevid(asym_alg, name_alg)?;
401-
ctx.flush_context(regen_idev.handle.into())?;
402-
// Flush after creating to make room for AK and EK and IAK
403-
regen_idev
404-
} else {
405-
info!("Collecting persisted IDevID.");
406-
ctx.idevid_from_handle(
407-
config.agent.idevid_handle.as_str(),
408-
config.agent.idevid_password.as_str(),
409-
)?
410-
};
411-
/// Check that recreated/collected IDevID key matches the one in the certificate
412-
if crypto::check_x509_key(
413-
&idevid_cert.clone().ok_or(Error::Other(
414-
"IAK/IDevID enabled but IDevID cert could not be used"
415-
.to_string(),
416-
))?,
417-
idevid.clone().public,
418-
)? {
419-
info!("IDevID matches certificate.");
420-
} else {
421-
error!("IDevID template does not match certificate. Check template in configuration.");
422-
return Err(Error::Configuration(config::KeylimeConfigError::Generic("IDevID template does not match certificate. Check template in configuration.".to_string())));
423-
}
424-
425-
/// IAK recreation/collection
426-
let iak = if config.agent.iak_handle.trim().is_empty() {
427-
/// If handle is not set in config, recreate IAK according to template
428-
info!("Recreating IAK.");
429-
ctx.create_iak(asym_alg, name_alg)?
430-
} else {
431-
/// If a handle has been set, try to collect from the handle
432-
/// If there is an IAK password, add the password to the handle
433-
info!("Collecting persisted IAK.");
434-
ctx.iak_from_handle(
435-
config.agent.iak_handle.as_str(),
436-
config.agent.iak_password.as_str(),
437-
)?
438-
};
439-
/// Check that recreated/collected IAK key matches the one in the certificate
440-
if crypto::check_x509_key(
441-
&iak_cert.clone().ok_or(Error::Other(
442-
"IAK/IDevID enabled but IAK cert could not be used"
443-
.to_string(),
444-
))?,
445-
iak.clone().public,
446-
)? {
447-
info!("IAK matches certificate.");
448-
} else {
449-
error!("IAK template does not match certificate. Check template in configuration.");
450-
return Err(Error::Configuration(config::KeylimeConfigError::Generic("IAK template does not match certificate. Check template in configuration.".to_string())));
451-
}
452-
453-
(Some(iak), Some(idevid))
454-
} else {
455-
(None, None)
456-
};
457-
458330
// Gather EK values and certs
459331
let ek_result = match config.agent.ek_handle.as_ref() {
460332
"" => ctx.create_ek(tpm_encryption_alg, None)?,
@@ -562,13 +434,33 @@ async fn main() -> Result<()> {
562434

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

565-
let (attest, signature) = if config.agent.enable_iak_idevid {
566-
let qualifying_data = config.agent.uuid.as_bytes();
567-
let (attest, signature) = ctx.certify_credential_with_iak(
568-
Data::try_from(qualifying_data).unwrap(), //#[allow_ci]
569-
ak_handle,
570-
iak.as_ref().unwrap().handle, //#[allow_ci]
571-
)?;
437+
// If using IAK/IDevID is enabled, obtain IAK/IDevID and respective certificates
438+
let mut device_id = if config.agent.enable_iak_idevid {
439+
Some(
440+
DeviceIDBuilder::new()
441+
.iak_handle(&config.agent.iak_handle)
442+
.iak_cert_path(&config.agent.iak_cert)
443+
.iak_password(&config.agent.iak_password)
444+
.iak_template(&config.agent.iak_idevid_template)
445+
.iak_asym_alg(&config.agent.iak_idevid_asymmetric_alg)
446+
.iak_hash_alg(&config.agent.iak_idevid_name_alg)
447+
.idevid_handle(&config.agent.idevid_handle)
448+
.idevid_cert_path(&config.agent.idevid_cert)
449+
.idevid_password(&config.agent.idevid_password)
450+
.idevid_template(&config.agent.iak_idevid_template)
451+
.idevid_asym_alg(&config.agent.iak_idevid_asymmetric_alg)
452+
.idevid_hash_alg(&config.agent.iak_idevid_name_alg)
453+
.build(&mut ctx)?,
454+
)
455+
} else {
456+
None
457+
};
458+
459+
let (attest, signature) = if let Some(dev_id) = &mut device_id {
460+
let qualifying_data = Data::try_from(agent_uuid.as_bytes())?;
461+
let (attest, signature) =
462+
dev_id.certify(qualifying_data, ak_handle, &mut ctx)?;
463+
572464
info!("AK certified with IAK.");
573465

574466
// // For debugging certify(), the following checks the generated signature
@@ -705,8 +597,8 @@ async fn main() -> Result<()> {
705597
{
706598
// Request keyblob material
707599
let keyblob = if config.agent.enable_iak_idevid {
708-
let (Some(iak), Some(idevid), Some(attest), Some(signature)) =
709-
(iak, idevid, attest, signature)
600+
let (Some(dev_id), Some(attest), Some(signature)) =
601+
(&device_id, attest, signature)
710602
else {
711603
error!(
712604
"IDevID and IAK are enabled but could not be generated"
@@ -725,15 +617,15 @@ async fn main() -> Result<()> {
725617
ek_result.ek_cert,
726618
&PublicBuffer::try_from(ak.public)?.marshall()?,
727619
Some(
728-
&PublicBuffer::try_from(iak.public.clone())?
620+
&PublicBuffer::try_from(dev_id.iak.public.clone())?
729621
.marshall()?,
730622
),
731623
Some(
732-
&PublicBuffer::try_from(idevid.public.clone())?
624+
&PublicBuffer::try_from(dev_id.idevid.public.clone())?
733625
.marshall()?,
734626
),
735-
idevid_cert,
736-
iak_cert,
627+
Some(dev_id.idevid_cert.clone()),
628+
Some(dev_id.iak_cert.clone()),
737629
Some(attest.marshall()?),
738630
Some(signature.marshall()?),
739631
mtls_cert,

keylime/src/crypto.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,10 @@ pub enum CryptoError {
5656
#[error("failed to create EcKey structure from public point")]
5757
ECKeyFromPublicPointError(#[source] openssl::error::ErrorStack),
5858

59+
/// File not found
60+
#[error("could not find file {0}")]
61+
FileNotFound(String),
62+
5963
/// Error creating file
6064
#[error("failed to create file {file}")]
6165
FSCreateError {
@@ -270,6 +274,15 @@ pub fn load_x509_pem(input_cert_path: &Path) -> Result<X509, CryptoError> {
270274
X509::from_pem(&contents).map_err(CryptoError::X509FromPEMError)
271275
}
272276

277+
/// Load a X509 certificate in PEM or DER format from a given path
278+
pub fn load_x509(path: &Path) -> Result<X509, CryptoError> {
279+
if path.exists() {
280+
load_x509_der(path).or(load_x509_pem(path))
281+
} else {
282+
Err(CryptoError::FileNotFound(path.display().to_string()))
283+
}
284+
}
285+
273286
/// Load X509 certificate chain in PEM format from file
274287
fn load_x509_cert_chain(
275288
input_cert_path: &Path,
@@ -368,7 +381,7 @@ pub fn hash(
368381
/// Check an x509 certificate contains a specific public key
369382
pub fn check_x509_key(
370383
cert: &X509,
371-
tpm_key: tss_esapi::structures::Public,
384+
tpm_key: &tss_esapi::structures::Public,
372385
) -> Result<bool, CryptoError> {
373386
// Id:RSA_PSS only added in rust-openssl from v0.10.59; remove this let and use Id::RSA_PSS after update
374387
// Id taken from https://boringssl.googlesource.com/boringssl/+/refs/heads/master/include/openssl/nid.h#4039
@@ -389,7 +402,7 @@ pub fn check_x509_key(
389402
let mut cert_n_str = format!("{:?}", cert_n);
390403
_ = cert_n_str.pop();
391404
_ = cert_n_str.remove(0);
392-
let key = SubjectPublicKeyInfo::try_from(tpm_key)
405+
let key = SubjectPublicKeyInfo::try_from(tpm_key.clone())
393406
.map_err(CryptoError::SubjectPublicKeyInfoFromRSAError)?;
394407
let key_der = picky_asn1_der::to_vec(&key)
395408
.map_err(CryptoError::SubjectPublicKeyInfoToDERError)?;
@@ -408,7 +421,7 @@ pub fn check_x509_key(
408421
let mut cert_n_str = format!("{:?}", cert_n);
409422
_ = cert_n_str.pop();
410423
_ = cert_n_str.remove(0);
411-
let key = SubjectPublicKeyInfo::try_from(tpm_key)
424+
let key = SubjectPublicKeyInfo::try_from(tpm_key.clone())
412425
.map_err(CryptoError::SubjectPublicKeyInfoFromRSAError)?;
413426
let key_der = picky_asn1_der::to_vec(&key)
414427
.map_err(CryptoError::SubjectPublicKeyInfoToDERError)?;
@@ -427,7 +440,7 @@ pub fn check_x509_key(
427440
let mut cert_n_str = format!("{:?}", cert_n);
428441
_ = cert_n_str.pop();
429442
_ = cert_n_str.remove(0);
430-
let key = SubjectPublicKeyInfo::try_from(tpm_key)
443+
let key = SubjectPublicKeyInfo::try_from(tpm_key.clone())
431444
.map_err(CryptoError::SubjectPublicKeyInfoFromECCError)?;
432445
let key_der = picky_asn1_der::to_vec(&key)
433446
.map_err(CryptoError::SubjectPublicKeyInfoToDERError)?;

0 commit comments

Comments
 (0)