fix(upgrade): U-01 — enforce pre-hashed minisign verification

This commit is contained in:
2026-09-19 09:41:29 +02:00
parent c7c0ed85f5
commit 78a9c233f8
2 changed files with 37 additions and 2 deletions
+4 -2
View File
@@ -64,14 +64,16 @@ impl Default for UpgradeOptions {
} }
} }
/// Überprüft eine Minisign-Signatur für gegebene Binärdaten mit dem angegebenen Minisign Public Key (S-02). /// Ü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<()> { pub fn verify_minisign_signature(data: &[u8], sig_str: &str, pubkey_str: &str) -> Result<()> {
let pubkey = minisign_verify::PublicKey::from_base64(pubkey_str) let pubkey = minisign_verify::PublicKey::from_base64(pubkey_str)
.map_err(|e| anyhow::anyhow!("Ungültiger öffentlicher Minisign-Schlüssel: {e}"))?; .map_err(|e| anyhow::anyhow!("Ungültiger öffentlicher Minisign-Schlüssel: {e}"))?;
let signature = minisign_verify::Signature::decode(sig_str) let signature = minisign_verify::Signature::decode(sig_str)
.map_err(|e| anyhow::anyhow!("Ungültiges Minisign-Signaturformat: {e}"))?; .map_err(|e| anyhow::anyhow!("Ungültiges Minisign-Signaturformat: {e}"))?;
pubkey pubkey
.verify(data, &signature, true) .verify(data, &signature, false)
.map_err(|e| anyhow::anyhow!("Minisign-Signaturprüfung FEHLGESCHLAGEN: {e}. Das Release-Manifest ist nicht vertrauenswürdig!"))?; .map_err(|e| anyhow::anyhow!("Minisign-Signaturprüfung FEHLGESCHLAGEN: {e}. Das Release-Manifest ist nicht vertrauenswürdig!"))?;
Ok(()) Ok(())
} }
+33
View File
@@ -75,3 +75,36 @@ fn test_upgrade_blocks_unofficial_url_without_insecure_flag() {
"Fehler muss Sicherheitsverstoß anzeigen: {err_msg}" "Fehler muss Sicherheitsverstoß anzeigen: {err_msg}"
); );
} }
#[test]
fn test_u01_reject_legacy_unhashed_signature() {
let payload = b"Hello Sanctum Release 0.7.0 Security Testing\n";
let sig_text = "\
untrusted comment: signature from minisign secret key\n\
RUSsVphPgr8155LCucDq8RzDmWMzWElzhBmHrS5p+qJlOCGU4AQpn2F28MVPFrnoGPYEHx7/6TlKg2b45DlYuBQ0+ASeLIzMLwc=\n\
trusted comment: timestamp:1789750897\tfile:test_payload.txt\thashed\n\
0l7KsNJkDTo2uOKL8UAiaJOWuhwhGTVZ5fn0JFMdxXE9riYixQO9YnBpSVqz8iCDhWrz8hJBnmUrIWnaRaXVCA==\n";
// Gültige pre-hashed Signatur muss weiterhin erfolgreich geprüft werden
assert!(verify_minisign_signature(payload, sig_text, SANCTUM_RELEASE_PUBKEY).is_ok());
// Modifiziere die Signatur, um eine Legacy-Signatur (Ed statt ED) zu simulieren
// In Base64 entspricht 'ED' (0x45, 0x44) dem Präfix 'RU'
// 'Ed' (0x45, 0x64) entspricht in Base64 dem Präfix 'RW'
let lines: Vec<&str> = sig_text.lines().collect();
let mut sig_line = lines[1].to_string();
assert!(sig_line.starts_with("RU"));
sig_line.replace_range(0..2, "RW");
let legacy_sig_text = format!(
"{}\n{}\n{}\n{}\n",
lines[0], sig_line, lines[2], lines[3]
);
let res = verify_minisign_signature(payload, &legacy_sig_text, SANCTUM_RELEASE_PUBKEY);
assert!(
res.is_err(),
"U-01: Legacy-Signaturen (ohne Pre-Hashing) müssen strikt abgewiesen werden"
);
}