Read MKB_RO not the padded MKB_RW; keep VID when keydb is disabled
- read_aacs_inputs / read_aacs_inputs_from_drive now read MKB_RO.inf first. MKB_RW.inf is a fixed ~128 MiB rewritable region that is mostly zero padding; reading it shipped 124 MiB of nothing. MKB_RO is the real, correctly-sized MKB (a few MB). Fall back to RW only if RO is absent. - disable_keydb no longer drops the Volume ID. A caller resolving Unit Keys out-of-band needs the VID (on-disc content read during the handshake). New resolve_vid_only builds a keys-free AacsState carrying just the VID + version metadata, so the disc reports 'encrypted, no keys' (resolved out-of-band) instead of discarding the VID.
This commit is contained in:
@@ -529,4 +529,67 @@ impl Disc {
|
|||||||
volume_id: handshake.map(|h| h.volume_id).unwrap_or([0u8; 16]),
|
volume_id: handshake.map(|h| h.volume_id).unwrap_or([0u8; 16]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build a keys-free AACS state that carries only the Volume ID (+ version
|
||||||
|
/// metadata), for callers that resolve Unit Keys out-of-band and have
|
||||||
|
/// disabled the local keydb. The VID is on-disc content read during the
|
||||||
|
/// handshake; preserving it here lets the out-of-band path use it. No keys
|
||||||
|
/// are present (`unit_keys` empty, `vuk` None), so the disc reports as
|
||||||
|
/// "encrypted, no keys" until the caller re-scans with a resolved Unit Key.
|
||||||
|
pub(super) fn resolve_vid_only(
|
||||||
|
udf_fs: &udf::UdfFs,
|
||||||
|
reader: &mut dyn SectorSource,
|
||||||
|
handshake: Option<&HandshakeResult>,
|
||||||
|
) -> Result<AacsState> {
|
||||||
|
use crate::aacs;
|
||||||
|
|
||||||
|
let uk_ro_data = udf_fs
|
||||||
|
.read_file(reader, "/AACS/Unit_Key_RO.inf")
|
||||||
|
.or_else(|_| udf_fs.read_file(reader, "/AACS/DUPLICATE/Unit_Key_RO.inf"))
|
||||||
|
.map_err(|_| Error::AacsNoKeys)?;
|
||||||
|
let dh = aacs::disc_hash(&uk_ro_data);
|
||||||
|
|
||||||
|
let cc = udf_fs
|
||||||
|
.read_file(reader, "/AACS/Content000.cer")
|
||||||
|
.or_else(|_| udf_fs.read_file(reader, "/AACS/Content001.cer"))
|
||||||
|
.ok()
|
||||||
|
.as_deref()
|
||||||
|
.and_then(aacs::parse_content_cert);
|
||||||
|
let bus_encryption = cc.as_ref().map(|c| c.bus_encryption).unwrap_or(false);
|
||||||
|
let version = match cc.as_ref().map(|c| c.version) {
|
||||||
|
Some(aacs::AacsVersion::V10) => 1,
|
||||||
|
Some(_) => 2,
|
||||||
|
None if bus_encryption => 2,
|
||||||
|
None => 1,
|
||||||
|
};
|
||||||
|
// MKB_RO is the correctly-sized copy; avoid reading the padded RW region.
|
||||||
|
let mkb_ver = udf_fs
|
||||||
|
.read_file(reader, "/AACS/MKB_RO.inf")
|
||||||
|
.or_else(|_| udf_fs.read_file(reader, "/AACS/MKB_RW.inf"))
|
||||||
|
.ok()
|
||||||
|
.as_deref()
|
||||||
|
.and_then(aacs::mkb_version);
|
||||||
|
|
||||||
|
tracing::warn!(
|
||||||
|
target: "freemkv::disc",
|
||||||
|
phase = "scan_aacs_vid_only",
|
||||||
|
disc_hash = %aacs::disc_hash_hex(&dh),
|
||||||
|
version,
|
||||||
|
bus_encryption,
|
||||||
|
has_vid = handshake.is_some(),
|
||||||
|
"keydb disabled — carrying VID only, keys resolved out-of-band"
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(AacsState {
|
||||||
|
version,
|
||||||
|
bus_encryption,
|
||||||
|
mkb_version: mkb_ver,
|
||||||
|
disc_hash: aacs::disc_hash_hex(&dh),
|
||||||
|
key_source: KeySource::ExternalUk,
|
||||||
|
vuk: None,
|
||||||
|
unit_keys: vec![],
|
||||||
|
read_data_key: handshake.and_then(|h| h.read_data_key),
|
||||||
|
volume_id: handshake.map(|h| h.volume_id).unwrap_or([0u8; 16]),
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-4
@@ -1173,9 +1173,12 @@ impl Disc {
|
|||||||
.read_file(&mut reader, "/AACS/Unit_Key_RO.inf")
|
.read_file(&mut reader, "/AACS/Unit_Key_RO.inf")
|
||||||
.or_else(|_| udf_fs.read_file(&mut reader, "/AACS/DUPLICATE/Unit_Key_RO.inf"))
|
.or_else(|_| udf_fs.read_file(&mut reader, "/AACS/DUPLICATE/Unit_Key_RO.inf"))
|
||||||
.map_err(|_| Error::AacsNoKeys)?;
|
.map_err(|_| Error::AacsNoKeys)?;
|
||||||
|
// Prefer MKB_RO: it's the real, correctly-sized MKB. MKB_RW is a
|
||||||
|
// fixed ~128 MiB rewritable region that is mostly zero padding — reading
|
||||||
|
// it ships 124 MiB of nothing. Fall back to RW only if RO is absent.
|
||||||
let mkb = udf_fs
|
let mkb = udf_fs
|
||||||
.read_file(&mut reader, "/AACS/MKB_RW.inf")
|
.read_file(&mut reader, "/AACS/MKB_RO.inf")
|
||||||
.or_else(|_| udf_fs.read_file(&mut reader, "/AACS/MKB_RO.inf"))
|
.or_else(|_| udf_fs.read_file(&mut reader, "/AACS/MKB_RW.inf"))
|
||||||
.map_err(|_| Error::AacsNoKeys)?;
|
.map_err(|_| Error::AacsNoKeys)?;
|
||||||
Ok((inf, mkb))
|
Ok((inf, mkb))
|
||||||
}
|
}
|
||||||
@@ -1191,9 +1194,12 @@ impl Disc {
|
|||||||
.read_file(&mut reader, "/AACS/Unit_Key_RO.inf")
|
.read_file(&mut reader, "/AACS/Unit_Key_RO.inf")
|
||||||
.or_else(|_| udf_fs.read_file(&mut reader, "/AACS/DUPLICATE/Unit_Key_RO.inf"))
|
.or_else(|_| udf_fs.read_file(&mut reader, "/AACS/DUPLICATE/Unit_Key_RO.inf"))
|
||||||
.map_err(|_| Error::AacsNoKeys)?;
|
.map_err(|_| Error::AacsNoKeys)?;
|
||||||
|
// Prefer MKB_RO: it's the real, correctly-sized MKB. MKB_RW is a
|
||||||
|
// fixed ~128 MiB rewritable region that is mostly zero padding — reading
|
||||||
|
// it ships 124 MiB of nothing. Fall back to RW only if RO is absent.
|
||||||
let mkb = udf_fs
|
let mkb = udf_fs
|
||||||
.read_file(&mut reader, "/AACS/MKB_RW.inf")
|
.read_file(&mut reader, "/AACS/MKB_RO.inf")
|
||||||
.or_else(|_| udf_fs.read_file(&mut reader, "/AACS/MKB_RO.inf"))
|
.or_else(|_| udf_fs.read_file(&mut reader, "/AACS/MKB_RW.inf"))
|
||||||
.map_err(|_| Error::AacsNoKeys)?;
|
.map_err(|_| Error::AacsNoKeys)?;
|
||||||
Ok((inf, mkb))
|
Ok((inf, mkb))
|
||||||
}
|
}
|
||||||
@@ -1226,6 +1232,15 @@ impl Disc {
|
|||||||
Ok(state) => (Some(state), None),
|
Ok(state) => (Some(state), None),
|
||||||
Err(e) => (None, Some(e)),
|
Err(e) => (None, Some(e)),
|
||||||
}
|
}
|
||||||
|
} else if opts.disable_keydb {
|
||||||
|
// Keydb disabled: keys are resolved out-of-band. Still capture the
|
||||||
|
// VID (read during the handshake) so the out-of-band path has it;
|
||||||
|
// carry no keys (disc reports "encrypted, no keys" until re-scanned
|
||||||
|
// with a resolved Unit Key).
|
||||||
|
match Self::resolve_vid_only(&udf_fs, reader, handshake.as_ref()) {
|
||||||
|
Ok(state) => (Some(state), None),
|
||||||
|
Err(e) => (None, Some(e)),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
match opts.resolve_keydb() {
|
match opts.resolve_keydb() {
|
||||||
Some(keydb_path) => {
|
Some(keydb_path) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user