Skip to content

Commit

Permalink
Generalize traversing a Clevis config
Browse files Browse the repository at this point in the history
Retain laziness in traversing the structure and early exit on error.

Signed-off-by: mulhern <[email protected]>
  • Loading branch information
mulkieran committed Oct 30, 2024
1 parent fd48484 commit 67f797f
Showing 1 changed file with 53 additions and 22 deletions.
75 changes: 53 additions & 22 deletions src/engine/strat_engine/crypt/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,17 @@ pub fn clevis_info_from_metadata(
pin_dispatch(&subjson, CLEVIS_RECURSION_LIMIT).map(Some)
}

/// Returns true if the Tang config has a thumbprint or an advertisement
/// or all Tang configs in the nested sss config have thumbprints or
/// advertisements.
fn all_tang_configs_have_url_trust_info(
fn traverse_clevis_config<T>(
pin: &str,
clevis_config: &Value,
recursion_limit: u64,
) -> StratisResult<bool> {
tang_func: &dyn Fn(&Map<String, Value>) -> StratisResult<T>,
tpm2_func: &dyn Fn(&Map<String, Value>) -> StratisResult<T>,
sss: &mut (&T, &mut dyn FnMut(T, T) -> StratisResult<T>),
) -> StratisResult<T>
where
T: Clone,
{
if recursion_limit == 0 {
return Err(StratisError::Msg(
"Reached the recursion limit for parsing nested SSS tokens".to_string(),
Expand All @@ -220,14 +223,7 @@ fn all_tang_configs_have_url_trust_info(

if pin == "tang" {
if let Some(obj) = clevis_config.as_object() {
Ok(obj
.get("thp")
.map(|val| val.as_str().is_some())
.or_else(|| {
obj.get("adv")
.map(|val| val.as_str().is_some() || val.as_object().is_some())
})
.unwrap_or(false))
tang_func(obj)
} else {
Err(StratisError::Msg(format!(
"configuration for Clevis is is not in JSON object format: {clevis_config}"
Expand All @@ -236,14 +232,16 @@ fn all_tang_configs_have_url_trust_info(
} else if pin == "sss" {
if let Some(obj) = clevis_config.as_object() {
if let Some(obj) = obj.get("pins").and_then(|val| val.as_object()) {
obj.iter().try_fold(true, |b, (pin, config)| {
Ok(
b && all_tang_configs_have_url_trust_info(
pin,
config,
recursion_limit - 1,
)?,
)
obj.iter().try_fold(sss.0.clone(), |acc, (pin, config)| {
let res = traverse_clevis_config(
pin,
config,
recursion_limit - 1,
tang_func,
tpm2_func,
sss,
)?;
sss.1(acc, res)
})
} else {
Err(StratisError::Msg(
Expand All @@ -256,12 +254,45 @@ fn all_tang_configs_have_url_trust_info(
)))
}
} else if pin == "tpm2" {
Ok(true)
if let Some(obj) = clevis_config.as_object() {
tpm2_func(obj)
} else {
Err(StratisError::Msg(format!(
"configuration for Clevis is is not in JSON object format: {clevis_config}"
)))
}
} else {
Err(StratisError::Msg(format!("Unrecognized pin {pin}")))
}
}

/// Returns true if the Tang config has a thumbprint or an advertisement
/// or all Tang configs in the nested sss config have thumbprints or
/// advertisements.
fn all_tang_configs_have_url_trust_info(
pin: &str,
clevis_config: &Value,
recursion_limit: u64,
) -> StratisResult<bool> {
traverse_clevis_config(
pin,
clevis_config,
recursion_limit,
&|obj| {
Ok(obj
.get("thp")
.map(|val| val.as_str().is_some())
.or_else(|| {
obj.get("adv")
.map(|val| val.as_str().is_some() || val.as_object().is_some())
})
.unwrap_or(false))
},
&|_| Ok(true),
&mut (&true, &mut |acc, premise| Ok(acc && premise)),
)
}

/// Interpret non-Clevis keys that may contain additional information about
/// how to configure Clevis when binding. Remove any expected non-Clevis keys
/// from the configuration.
Expand Down

0 comments on commit 67f797f

Please sign in to comment.