Skip to content

Commit d027299

Browse files
Isaac-Matthewsansasaki
authored andcommitted
added use of persisted IAK and IDevID and authorisation values
Signed-off-by: Isaac-Matthews <[email protected]>
1 parent f0aab22 commit d027299

File tree

4 files changed

+151
-22
lines changed

4 files changed

+151
-22
lines changed

keylime-agent.conf

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ tpm_signing_alg = "rsassa"
228228
ek_handle = "generate"
229229

230230
# Enable IDevID and IAK usage
231-
enable_iak_idevid = true
231+
enable_iak_idevid = false
232232

233233
# Select IDevID and IAK templates or algorithms for regenerating the keys.
234234
# By default the template will be detected automatically from the certificates. This will happen if iak_idevid_template is left empty or set as "default" or "detect".

keylime-agent/src/config.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -341,19 +341,16 @@ impl EnvConfig {
341341
);
342342
}
343343
if let Some(ref v) = self.idevid_password {
344-
_ = agent.insert(
345-
"idevid_password".to_string(),
346-
v.to_string().into(),
347-
);
344+
_ = agent
345+
.insert("idevid_password".to_string(), v.to_string().into());
348346
}
349347
if let Some(ref v) = self.iak_password {
350-
_ = agent.insert(
351-
"iak_password".to_string(),
352-
v.to_string().into(),
353-
);
348+
_ = agent
349+
.insert("iak_password".to_string(), v.to_string().into());
354350
}
355351
if let Some(ref v) = self.idevid_handle {
356-
_ = agent.insert("idevid_handle".to_string(), v.to_string().into());
352+
_ = agent
353+
.insert("idevid_handle".to_string(), v.to_string().into());
357354
}
358355
if let Some(ref v) = self.iak_handle {
359356
_ = agent.insert("iak_handle".to_string(), v.to_string().into());

keylime-agent/src/main.rs

+39-11
Original file line numberDiff line numberDiff line change
@@ -378,8 +378,9 @@ async fn main() -> Result<()> {
378378
iak_cert = None;
379379
idevid_cert = None;
380380
}
381-
/// Regenerate the IAK and IDevID and check that the keys match the certificates that have been loaded
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
382382
let (iak, idevid) = if config.agent.enable_iak_idevid {
383+
/// Try to detect which template has been used by checking the certificate
383384
let (asym_alg, name_alg) = tpm::get_idevid_template(
384385
&crypto::match_cert_to_template(
385386
&iak_cert.clone().ok_or(Error::Other(
@@ -392,31 +393,58 @@ async fn main() -> Result<()> {
392393
config.agent.iak_idevid_name_alg.as_str(),
393394
)?;
394395

395-
let idevid = ctx.create_idevid(asym_alg, name_alg)?;
396-
info!("IDevID created.");
397-
// Flush after creating to make room for AK and EK and IAK
398-
ctx.as_mut().flush_context(idevid.handle.into())?;
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.as_mut().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
399412
if crypto::check_x509_key(
400413
&idevid_cert.clone().ok_or(Error::Other(
401-
"IAK/IDevID enabled but cert could not be used".to_string(),
414+
"IAK/IDevID enabled but IDevID cert could not be used"
415+
.to_string(),
402416
))?,
403417
idevid.clone().public,
404418
)? {
405-
info!("Regenerated IDevID matches certificate.");
419+
info!("IDevID matches certificate.");
406420
} else {
407421
error!("IDevID template does not match certificate. Check template in configuration.");
408422
return Err(Error::Configuration("IDevID template does not match certificate. Check template in configuration.".to_string()));
409423
}
410424

411-
let iak = ctx.create_iak(asym_alg, name_alg)?;
412-
info!("IAK created.");
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
413440
if crypto::check_x509_key(
414441
&iak_cert.clone().ok_or(Error::Other(
415-
"IAK/IDevID enabled but cert could not be used".to_string(),
442+
"IAK/IDevID enabled but IAK cert could not be used"
443+
.to_string(),
416444
))?,
417445
iak.clone().public,
418446
)? {
419-
info!("Regenerated IAK matches certificate.");
447+
info!("IAK matches certificate.");
420448
} else {
421449
error!("IAK template does not match certificate. Check template in configuration.");
422450
return Err(Error::Configuration("IAK template does not match certificate. Check template in configuration.".to_string()));

keylime/src/tpm.rs

+105-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ use tss_esapi::{
4343
structure_tags::AttestationType,
4444
},
4545
structures::{
46-
Attest, AttestInfo, Data, Digest, DigestValues, EccParameter,
46+
Attest, AttestInfo, Auth, Data, Digest, DigestValues, EccParameter,
4747
EccPoint, EccScheme, EncryptedSecret, HashScheme, IdObject,
4848
KeyDerivationFunctionScheme, Name, PcrSelectionList,
4949
PcrSelectionListBuilder, PcrSlot, PublicBuilder,
@@ -140,6 +140,13 @@ pub enum TpmError {
140140
source: tss_esapi::Error,
141141
},
142142

143+
/// Error setting auth for persistent TPM handle
144+
#[error("Error setting auth for persistent TPM handle {handle}")]
145+
TSSHandleSetAuthError {
146+
handle: String,
147+
source: tss_esapi::Error,
148+
},
149+
143150
/// Error returned in case of error creating new Primary Key
144151
#[error("Error creating primary key")]
145152
TSSCreatePrimaryError { source: tss_esapi::Error },
@@ -339,6 +346,10 @@ pub enum TpmError {
339346
#[error("base64 decode error")]
340347
Base64Decode(#[from] base64::DecodeError),
341348

349+
/// Hex decoding error
350+
#[error("hex decode error")]
351+
HexDecodeError(String),
352+
342353
/// Malformed PCR selection mask
343354
#[error("Malformed PCR selection mask: {0}")]
344355
MalformedPCRSelectionMask(String),
@@ -613,6 +624,99 @@ impl Context {
613624
Ok(ak_handle)
614625
}
615626

627+
/// Load a key handle from a string of the handle location
628+
/// If a password is supplied, authorise the handle
629+
/// # Arguments
630+
///
631+
/// `handle` : The string of the handle, eg. from config
632+
/// `password` ; The string password, to be converted to hex if there is the "hex:" prefix
633+
///
634+
/// # Return
635+
/// The corresponding KeyHandle, or a TPMError
636+
fn get_key_handle(
637+
&mut self,
638+
handle: &str,
639+
password: &str,
640+
) -> Result<KeyHandle> {
641+
let handle = u32::from_str_radix(handle.trim_start_matches("0x"), 16)
642+
.map_err(|source| TpmError::NumParse {
643+
origin: handle.to_string(),
644+
source,
645+
})?;
646+
let key_handle: KeyHandle = self
647+
.inner
648+
.tr_from_tpm_public(TpmHandle::Persistent(
649+
PersistentTpmHandle::new(handle).map_err(|source| {
650+
TpmError::TSSNewPersistentHandleError {
651+
handle: handle.to_string(),
652+
source,
653+
}
654+
})?,
655+
))
656+
.map_err(|source| TpmError::TSSHandleFromPersistentHandleError {
657+
handle: handle.to_string(),
658+
source,
659+
})?
660+
.into();
661+
if !password.is_empty() {
662+
let auth = if password.starts_with("hex:") {
663+
let (_, hex_password) = password.split_at(4);
664+
let decoded_password =
665+
hex::decode(hex_password).map_err(|_| {
666+
TpmError::HexDecodeError(
667+
"Hex decode error for identity auth value."
668+
.to_string(),
669+
)
670+
})?;
671+
Auth::try_from(decoded_password)?
672+
} else {
673+
Auth::try_from(password.as_bytes())?
674+
};
675+
self.as_mut().tr_set_auth(key_handle.into(), auth).map_err(
676+
|source| TpmError::TSSHandleSetAuthError {
677+
handle: handle.to_string(),
678+
source,
679+
},
680+
)?;
681+
};
682+
683+
Ok(key_handle)
684+
}
685+
686+
/// Create an IDevID object from one persisted in TPM using its handle
687+
pub fn idevid_from_handle(
688+
&mut self,
689+
handle: &str,
690+
password: &str,
691+
) -> Result<IDevIDResult> {
692+
let idevid_handle = self.get_key_handle(handle, password)?;
693+
let (idevid_pub, _, _) = self
694+
.inner
695+
.read_public(idevid_handle)
696+
.map_err(|source| TpmError::TSSReadPublicError { source })?;
697+
Ok(IDevIDResult {
698+
public: idevid_pub,
699+
handle: idevid_handle,
700+
})
701+
}
702+
703+
/// Create an IAK object from one persisted in TPM using its handle
704+
pub fn iak_from_handle(
705+
&mut self,
706+
handle: &str,
707+
password: &str,
708+
) -> Result<IAKResult> {
709+
let iak_handle = self.get_key_handle(handle, password)?;
710+
let (iak_pub, _, _) = self
711+
.inner
712+
.read_public(iak_handle)
713+
.map_err(|source| TpmError::TSSReadPublicError { source })?;
714+
Ok(IAKResult {
715+
public: iak_pub,
716+
handle: iak_handle,
717+
})
718+
}
719+
616720
/// Creates an IDevID
617721
pub fn create_idevid(
618722
&mut self,

0 commit comments

Comments
 (0)