fix(upgrade): U-03 — configure secondary backup release public key
This commit is contained in:
+25
-1
@@ -20,6 +20,8 @@ pub const OFFICIAL_UPGRADE_URL: &str = "https://gitea.pansi.eu";
|
|||||||
pub const CHECKSUM_ASSET_NAME: &str = "SHA256SUMS.txt";
|
pub const CHECKSUM_ASSET_NAME: &str = "SHA256SUMS.txt";
|
||||||
pub const CHECKSUM_SIG_ASSET_NAME: &str = "SHA256SUMS.txt.minisig";
|
pub const CHECKSUM_SIG_ASSET_NAME: &str = "SHA256SUMS.txt.minisig";
|
||||||
pub const SANCTUM_RELEASE_PUBKEY: &str = "RWSsVphPgr8157M9rTPkWDw3c0qIjc7xi28Gmw+cIWbMipOy4L6ToJEU";
|
pub const SANCTUM_RELEASE_PUBKEY: &str = "RWSsVphPgr8157M9rTPkWDw3c0qIjc7xi28Gmw+cIWbMipOy4L6ToJEU";
|
||||||
|
pub const SANCTUM_RELEASE_PUBKEY_BACKUP: &str =
|
||||||
|
"RWQEeUSLlX2p4EPUPN1GjeUv34qA0p2B6wJYzcou5oOwAkkw0f+r9FmZ";
|
||||||
|
|
||||||
/// Repräsentiert ein Asset in einem Gitea-Release
|
/// Repräsentiert ein Asset in einem Gitea-Release
|
||||||
#[derive(Debug, Deserialize, Clone)]
|
#[derive(Debug, Deserialize, Clone)]
|
||||||
@@ -122,6 +124,28 @@ pub fn validate_trusted_comment_version(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Überprüft eine Minisign-Signatur für ein Release-Manifest.
|
||||||
|
///
|
||||||
|
/// Prüft primär gegen `SANCTUM_RELEASE_PUBKEY`. Falls diese Verifikation fehlschlägt,
|
||||||
|
/// wird transparent gegen den sekundären Backup-Schlüssel `SANCTUM_RELEASE_PUBKEY_BACKUP`
|
||||||
|
/// geprüft (U-03), um unterbrechungsfreie Schlüsselrotationen zu ermöglichen.
|
||||||
|
pub fn verify_release_manifest_signature(data: &[u8], sig_str: &str) -> Result<String> {
|
||||||
|
match verify_minisign_signature(data, sig_str, SANCTUM_RELEASE_PUBKEY) {
|
||||||
|
Ok(comment) => Ok(comment),
|
||||||
|
Err(primary_err) => {
|
||||||
|
match verify_minisign_signature(data, sig_str, SANCTUM_RELEASE_PUBKEY_BACKUP) {
|
||||||
|
Ok(comment) => {
|
||||||
|
tracing::info!(
|
||||||
|
"Minisign-Signatur erfolgreich mit sekundärem Backup-Schlüssel verifiziert."
|
||||||
|
);
|
||||||
|
Ok(comment)
|
||||||
|
}
|
||||||
|
Err(_) => Err(primary_err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Erkannter Paketmanager
|
/// Erkannter Paketmanager
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum PackageManager {
|
pub enum PackageManager {
|
||||||
@@ -545,7 +569,7 @@ pub fn run_upgrade(options: &UpgradeOptions) -> Result<()> {
|
|||||||
" {} Verifiziere Minisign-Signatur gegen eingebetteten Herstellerschlüssel ...",
|
" {} Verifiziere Minisign-Signatur gegen eingebetteten Herstellerschlüssel ...",
|
||||||
ui::dim("[-]")
|
ui::dim("[-]")
|
||||||
);
|
);
|
||||||
let trusted_comment = verify_minisign_signature(sums_content.as_bytes(), &sig_content, SANCTUM_RELEASE_PUBKEY)
|
let trusted_comment = verify_release_manifest_signature(sums_content.as_bytes(), &sig_content)
|
||||||
.context("Minisign-Signaturprüfung für Prüfsummendatei FEHLGESCHLAGEN! Release ist nicht vertrauenswürdig.")?;
|
.context("Minisign-Signaturprüfung für Prüfsummendatei FEHLGESCHLAGEN! Release ist nicht vertrauenswürdig.")?;
|
||||||
validate_trusted_comment_version(&trusted_comment, remote_tag)?;
|
validate_trusted_comment_version(&trusted_comment, remote_tag)?;
|
||||||
println!(
|
println!(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use sanctum::upgrade::{
|
use sanctum::upgrade::{
|
||||||
run_upgrade, validate_trusted_comment_version, verify_minisign_signature, UpgradeOptions,
|
run_upgrade, validate_trusted_comment_version, verify_minisign_signature,
|
||||||
SANCTUM_RELEASE_PUBKEY,
|
verify_release_manifest_signature, UpgradeOptions, SANCTUM_RELEASE_PUBKEY,
|
||||||
|
SANCTUM_RELEASE_PUBKEY_BACKUP,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -144,3 +145,54 @@ fn test_u02_reject_mismatched_release_tag_replay() {
|
|||||||
assert!(res2.is_err());
|
assert!(res2.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_u03_verify_signature_with_backup_key_fallback() {
|
||||||
|
let payload = b"Hello Sanctum Release 0.8.0 Backup Key Testing\n";
|
||||||
|
let backup_sig = "\
|
||||||
|
untrusted comment: signature from minisign secret key\n\
|
||||||
|
RUQEeUSLlX2p4HrXDO2TYykyNK0C41Vdrq6MIts14mQgNDClGC2RkBV3jHRbP7IclWv+h/IuzvyYi9yz8/RqfhpDVwhqtvC02gk=\n\
|
||||||
|
trusted comment: version:0.8.0\n\
|
||||||
|
zjZAS4uy1PH+0S9KQ0EU435lpBczU3lULyS5SkWf093iCEBc1ULiscwE5gWkEkex3ecPdRugopT+fKaZBQQnBg==\n";
|
||||||
|
|
||||||
|
// 1. Direct verification against primary key MUST fail (key rotation scenario)
|
||||||
|
let prim_res = verify_minisign_signature(payload, backup_sig, SANCTUM_RELEASE_PUBKEY);
|
||||||
|
assert!(
|
||||||
|
prim_res.is_err(),
|
||||||
|
"Backup-Signatur darf nicht gegen den Primärschlüssel verifizieren"
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2. Direct verification against backup key MUST succeed
|
||||||
|
let back_res = verify_minisign_signature(payload, backup_sig, SANCTUM_RELEASE_PUBKEY_BACKUP);
|
||||||
|
assert!(
|
||||||
|
back_res.is_ok(),
|
||||||
|
"Backup-Signatur muss gegen SANCTUM_RELEASE_PUBKEY_BACKUP gültig sein: {:?}",
|
||||||
|
back_res.err()
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. Fallback verification via verify_release_manifest_signature MUST succeed transparently
|
||||||
|
let fallback_res = verify_release_manifest_signature(payload, backup_sig);
|
||||||
|
assert!(
|
||||||
|
fallback_res.is_ok(),
|
||||||
|
"verify_release_manifest_signature muss via Backup-Schlüssel erfolgreich sein"
|
||||||
|
);
|
||||||
|
assert_eq!(fallback_res.unwrap(), "version:0.8.0");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_u03_verify_signature_rejects_untrusted_third_party_key() {
|
||||||
|
let fake_sig = "\
|
||||||
|
untrusted comment: signature from minisign secret key\n\
|
||||||
|
RUQEeUSLlX2p4HrXDO2TYykyNK0C41Vdrq6MIts14mQgNDClGC2RkBV3jHRbP7IclWv+h/IuzvyYi9yz8/RqfhpDVwhqtvC02gk=\n\
|
||||||
|
trusted comment: version:0.8.0\n\
|
||||||
|
zjZAS4uy1PH+0S9KQ0EU435lpBczU3lULyS5SkWf093iCEBc1ULiscwE5gWkEkex3ecPdRugopT+fKaZBQQnBg==\n";
|
||||||
|
|
||||||
|
// Tampered payload with neither primary nor backup key matching
|
||||||
|
let tampered = b"Tampered data not signed by either key";
|
||||||
|
let res = verify_release_manifest_signature(tampered, fake_sig);
|
||||||
|
assert!(
|
||||||
|
res.is_err(),
|
||||||
|
"Weder Primär- noch Backup-Schlüssel dürfen manipulierte Nutzdaten akzeptieren"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user