in tuftool/src/root.rs [306:400]
fn sign(
path: &Path,
key_source: &[Box<dyn KeySource>],
cross_sign: Option<PathBuf>,
ignore_threshold: bool,
) -> Result<()> {
let root: Signed<Root> = load_file(path)?;
// get the root based on cross-sign
let loaded_root = match cross_sign {
None => root.clone(),
Some(cross_sign_root) => load_file(&cross_sign_root)?,
};
// sign the root
let mut signed_root = SignedRole::new(
root.signed.clone(),
&KeyHolder::Root(loaded_root.signed),
key_source,
&SystemRandom::new(),
)
.context(error::SignRootSnafu { path })?;
// append the existing signatures if present
if !root.signatures.is_empty() {
signed_root = signed_root
.add_old_signatures(root.signatures)
.context(error::SignRootSnafu { path })?;
}
// Quick check that root is signed by enough key IDs, in all its roles.
for (roletype, rolekeys) in &signed_root.signed().signed.roles {
let threshold = rolekeys.threshold.get();
let keyids = rolekeys.keyids.len();
if threshold > keyids as u64 {
// Return an error when the referenced root.json isn't compliant with the
// threshold. The referenced file could be a root.json used for cross signing,
// which wasn't signed with enough keys.
if !ignore_threshold {
return Err(error::Error::UnstableRoot {
role: *roletype,
threshold,
actual: keyids,
});
}
// Print out a warning to let the user know that the referenced root.json
// file isn't compliant with the threshold specified for the role type.
warn!(
"Loaded unstable root, role '{}' contains '{}' keys, expected '{}'",
*roletype, threshold, keyids
);
}
}
// Signature check for root
let threshold = signed_root
.signed()
.signed
.roles
.get(&RoleType::Root)
.ok_or(error::Error::UnstableRoot {
// The code should never reach this point
role: RoleType::Root,
threshold: 0,
actual: 0,
})?
.threshold
.get();
let signature_count = signed_root.signed().signatures.len();
if threshold > signature_count as u64 {
// Return an error when the "ignore-threshold" flag wasn't set
if !ignore_threshold {
return Err(error::Error::SignatureRoot {
threshold,
signature_count,
});
}
// Print out a warning letting the user know that the target file isn't compliant with
// the threshold used for the root role.
warn!(
"The root.json file requires at least {} signatures, the target file contains {}",
threshold, signature_count
);
}
// Use `tempfile::NamedTempFile::persist` to perform an atomic file write.
let parent = path.parent().context(error::PathParentSnafu { path })?;
let mut writer =
NamedTempFile::new_in(parent).context(error::FileTempCreateSnafu { path: parent })?;
writer
.write_all(signed_root.buffer())
.context(error::FileWriteSnafu { path })?;
writer
.persist(path)
.context(error::FilePersistSnafu { path })?;
Ok(())
}