fix(upgrade): U-02 — validate version in minisign trusted comment against release tag

This commit is contained in:
2026-09-19 09:43:39 +02:00
parent 78a9c233f8
commit 8dd54494b0
4 changed files with 87 additions and 6 deletions
+48 -3
View File
@@ -67,7 +67,8 @@ impl Default for UpgradeOptions {
/// Überprüft eine Minisign-Signatur für gegebene Binärdaten mit dem angegebenen Minisign Public Key (U-01).
///
/// Erzwingt strikt Pre-Hashing (`allow_legacy = false`), um Malleability- und Längenangriffe auszuschließen.
pub fn verify_minisign_signature(data: &[u8], sig_str: &str, pubkey_str: &str) -> Result<()> {
/// Gibt bei erfolgreicher Verifikation den kryptografisch authentifizierten `trusted comment` zurück.
pub fn verify_minisign_signature(data: &[u8], sig_str: &str, pubkey_str: &str) -> Result<String> {
let pubkey = minisign_verify::PublicKey::from_base64(pubkey_str)
.map_err(|e| anyhow::anyhow!("Ungültiger öffentlicher Minisign-Schlüssel: {e}"))?;
let signature = minisign_verify::Signature::decode(sig_str)
@@ -75,6 +76,49 @@ pub fn verify_minisign_signature(data: &[u8], sig_str: &str, pubkey_str: &str) -
pubkey
.verify(data, &signature, false)
.map_err(|e| anyhow::anyhow!("Minisign-Signaturprüfung FEHLGESCHLAGEN: {e}. Das Release-Manifest ist nicht vertrauenswürdig!"))?;
Ok(signature.trusted_comment().to_string())
}
/// Extrahiert die Versionsnummer aus dem Trusted Comment einer Minisign-Signatur und
/// validiert sie gegen das erwartete Release-Tag (U-02).
pub fn validate_trusted_comment_version(
trusted_comment: &str,
expected_release: &str,
) -> Result<()> {
let clean_expected = expected_release
.trim()
.trim_start_matches(|c| c == 'v' || c == 'V');
if clean_expected.is_empty() {
bail!("Erwartetes Release-Tag darf nicht leer sein.");
}
// Durchsuche die Tokens des Trusted Comments (getrennt durch Tabs oder Leerzeichen)
let found = trusted_comment.split_whitespace().any(|token| {
let val = if let Some(stripped) = token.strip_prefix("version:") {
stripped
} else if let Some(stripped) = token.strip_prefix("release:") {
stripped
} else if let Some(stripped) = token.strip_prefix("tag:") {
stripped
} else {
token
};
let clean_val = val.trim_start_matches(|c| c == 'v' || c == 'V');
clean_val == clean_expected
});
if !found {
bail!(
"Signatur-Validierungsfehler (U-02): Der kryptografisch gesicherte Trusted Comment \
'{}' stimmt nicht mit der erwarteten Release-Version '{}' überein! \
Möglicher Replay-Angriff mit einer älteren signierten Prüfsummendatei.",
trusted_comment.trim(),
expected_release
);
}
Ok(())
}
@@ -501,10 +545,11 @@ pub fn run_upgrade(options: &UpgradeOptions) -> Result<()> {
" {} Verifiziere Minisign-Signatur gegen eingebetteten Herstellerschlüssel ...",
ui::dim("[-]")
);
verify_minisign_signature(sums_content.as_bytes(), &sig_content, SANCTUM_RELEASE_PUBKEY)
let trusted_comment = verify_minisign_signature(sums_content.as_bytes(), &sig_content, SANCTUM_RELEASE_PUBKEY)
.context("Minisign-Signaturprüfung für Prüfsummendatei FEHLGESCHLAGEN! Release ist nicht vertrauenswürdig.")?;
validate_trusted_comment_version(&trusted_comment, remote_tag)?;
println!(
" • Signatur: {} (Minisign Ed25519)",
" • Signatur: {} (Minisign Ed25519, Version validiert)",
ui::green("Gültig")
);