keydb: require content samples so per-disc UK entries are ciphertext-validated
A keydb can hand out a per-disc terminal Key::Unit (a UK entry keyed on disc_hash). Unlike a derived key (Device/Processing/Media/Volume), a terminal UK is applied as-is by Disc::decrypt_with: it is NOT re-derived through the MKB-verified AACS resolver, so a UK entry whose hash matches the disc but whose key bytes are wrong is only disproved by descrambling real ciphertext. KeydbSource inherited the default needs_samples() == false, so on the autorip auto-resume / mux-worker path (which samples units only when some source reports needs_samples()) a keydb-only resolve ran with empty samples and committed a wrong UK as success, muxing undecryptable video while reporting done. The CLI was unaffected because it always samples. Override needs_samples() to true on KeydbSource so every consumer samples encrypted units before resolving and a wrong keydb UK is rejected on all paths. Regression test asserts the override.
This commit is contained in:
@@ -106,6 +106,21 @@ impl KeySource for KeydbSource {
|
|||||||
KeydbSource::host_certs(self)
|
KeydbSource::host_certs(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The keydb can hand out a per-disc **terminal** `Key::Unit` (a UK entry
|
||||||
|
/// keyed on `disc_hash` alone — see `candidates_from`). Unlike a derived key
|
||||||
|
/// (Device/Processing/Media/Volume), a terminal UK is applied as-is by
|
||||||
|
/// `Disc::decrypt_with`: it is NOT re-derived through the MKB-verified AACS
|
||||||
|
/// resolver, so a UK entry whose hash matches the disc but whose key bytes
|
||||||
|
/// are wrong would commit and mux undecryptable video as "success". The only
|
||||||
|
/// thing that disproves a wrong UK is descrambling real ciphertext, so this
|
||||||
|
/// source requires content samples — without them `decrypt_with` skips
|
||||||
|
/// validation and the wrong UK is taken. Returning `true` makes every
|
||||||
|
/// consumer (autorip resume/mux-worker AND the CLI) sample units before
|
||||||
|
/// resolving, so a keydb UK is ciphertext-validated on every path.
|
||||||
|
fn needs_samples(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
fn next_key(&mut self, inputs: &DiscInputs) -> Option<Key> {
|
fn next_key(&mut self, inputs: &DiscInputs) -> Option<Key> {
|
||||||
// On the first ask, parse the keydb once and build the ordered candidate
|
// On the first ask, parse the keydb once and build the ordered candidate
|
||||||
// list; later asks just advance the cursor. A missing/unreadable keydb
|
// list; later asks just advance the cursor. A missing/unreadable keydb
|
||||||
@@ -232,6 +247,22 @@ mod tests {
|
|||||||
assert!(KeydbSource::candidates_from(&db, &inputs("0xaabb")).is_empty());
|
assert!(KeydbSource::candidates_from(&db, &inputs("0xaabb")).is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Regression: a keydb can hand out a per-disc terminal `Key::Unit` that
|
||||||
|
/// `Disc::decrypt_with` applies WITHOUT re-deriving through the MKB-verified
|
||||||
|
/// AACS resolver. The only thing that disproves a wrong UK is descrambling
|
||||||
|
/// ciphertext, so the source MUST request content samples — otherwise the
|
||||||
|
/// autorip resume/mux-worker path (which only samples when some source
|
||||||
|
/// reports `needs_samples()`) resolves with empty samples and commits a
|
||||||
|
/// wrong UK as success. Was `false` (inherited default); must be `true`.
|
||||||
|
#[test]
|
||||||
|
fn keydb_source_needs_samples() {
|
||||||
|
let src = KeydbSource::new("/nonexistent/path/keydb.cfg");
|
||||||
|
assert!(
|
||||||
|
src.needs_samples(),
|
||||||
|
"keydb emits terminal Key::Unit entries that need ciphertext validation"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// No keydb (or a LibreDrive deployment) → no host credentials, not an
|
/// No keydb (or a LibreDrive deployment) → no host credentials, not an
|
||||||
/// error. (The positive parse is NOT tested here — it would require host
|
/// error. (The positive parse is NOT tested here — it would require host
|
||||||
/// key material, which must never appear in code.)
|
/// key material, which must never appear in code.)
|
||||||
|
|||||||
Reference in New Issue
Block a user