scan: genericize the caller-supplied unit-key docs (no external-source naming)

The ScanOptions.unit_key path is a generic primitive — a caller-supplied Unit
Key that bypasses keydb lookup. Doc comments + a tracing log named a specific
external source; reworded to neutral 'out-of-band / external key service' so
the library makes no assumptions about where the key came from.
This commit is contained in:
MattJackson
2026-06-02 13:00:11 -07:00
parent 9f209fe066
commit 94ab7bc73c
4 changed files with 18 additions and 20 deletions
+1 -1
View File
@@ -15,7 +15,7 @@
//! fastest/closest first. //! fastest/closest first.
//! //!
//! Default impls return empty / `None` so backends only override //! Default impls return empty / `None` so backends only override
//! the methods they actually support — an HTTP keyserver might //! the methods they actually support — an external key service might
//! implement only `lookup_disc_by_hash`, while a local file might //! implement only `lookup_disc_by_hash`, while a local file might
//! implement all five. //! implement all five.
//! //!
+2 -2
View File
@@ -468,7 +468,7 @@ impl Disc {
}) })
} }
/// Resolve encryption from a caller-supplied Unit Key (the keyserver /// Resolve encryption from a caller-supplied Unit Key (the external key service
/// path). No keydb, no derivation: read `Unit_Key_RO.inf` for the disc /// path). No keydb, no derivation: read `Unit_Key_RO.inf` for the disc
/// hash + version/bus-encryption flags, then use `unit_key` directly as /// hash + version/bus-encryption flags, then use `unit_key` directly as
/// CPS unit 1's decryption key. The handshake (if any) still supplies the /// CPS unit 1's decryption key. The handshake (if any) still supplies the
@@ -514,7 +514,7 @@ impl Disc {
disc_hash = %aacs::disc_hash_hex(&dh), disc_hash = %aacs::disc_hash_hex(&dh),
version, version,
bus_encryption, bus_encryption,
"using caller-supplied unit key (keyserver path)" "using caller-supplied unit key"
); );
Ok(AacsState { Ok(AacsState {
+14 -16
View File
@@ -912,7 +912,7 @@ pub enum KeySource {
/// Pre-decrypted unit keys taken directly from KEYDB by disc hash. /// Pre-decrypted unit keys taken directly from KEYDB by disc hash.
/// No VUK present in the entry — `AacsState::vuk` is `None`. /// No VUK present in the entry — `AacsState::vuk` is `None`.
KeyDbUnitKeys, KeyDbUnitKeys,
/// Unit key supplied directly by the caller (the keyserver path). /// Unit key supplied directly by the caller (the external Unit Key path).
/// No keydb, no derivation — `AacsState::vuk` is `None`. /// No keydb, no derivation — `AacsState::vuk` is `None`.
ExternalUk, ExternalUk,
} }
@@ -945,12 +945,11 @@ pub struct ScanOptions {
/// Path to KEYDB.cfg for AACS key lookup. /// Path to KEYDB.cfg for AACS key lookup.
/// If None, searches standard locations ($HOME/.config/aacs/ and /etc/aacs/). /// If None, searches standard locations ($HOME/.config/aacs/ and /etc/aacs/).
pub keydb_path: Option<std::path::PathBuf>, pub keydb_path: Option<std::path::PathBuf>,
/// Caller-supplied Unit Key — the second, mutually-exclusive key source /// Caller-supplied Unit Key — an alternative to keydb lookup. When set,
/// (the online-keyserver path). When set, libfreemkv skips keydb lookup /// libfreemkv skips keydb lookup and all derivation and uses this key
/// and all derivation and uses this key directly to decrypt. Takes /// directly to decrypt; it takes precedence over `keydb_path`. The caller
/// precedence over `keydb_path` if both are set. The caller obtains it /// obtains the key however it likes; libfreemkv stays free of any network
/// however it likes (e.g. POSTing the disc's `Unit_Key_RO.inf` + MKB to a /// dependency.
/// keyserver); libfreemkv stays free of any network dependency.
pub unit_key: Option<[u8; 16]>, pub unit_key: Option<[u8; 16]>,
} }
@@ -1152,10 +1151,10 @@ impl Disc {
} }
/// Read a disc's AACS key-input files from an ISO image: returns /// Read a disc's AACS key-input files from an ISO image: returns
/// `(Unit_Key_RO.inf, MKB)` raw bytes. For callers that resolve keys /// `(Unit_Key_RO.inf, MKB)` raw bytes. For callers that resolve a Unit Key
/// out-of-band (the keyserver path) — POST these to the keyserver, get the /// out-of-band: obtain the key however you like, then scan with
/// Unit Key, then scan with `ScanOptions { unit_key: Some(uk), .. }`. /// `ScanOptions { unit_key: Some(uk), .. }`. libfreemkv never makes a
/// libfreemkv itself never makes the network call. /// network call.
pub fn read_aacs_inputs(iso_path: &std::path::Path) -> Result<(Vec<u8>, Vec<u8>)> { pub fn read_aacs_inputs(iso_path: &std::path::Path) -> Result<(Vec<u8>, Vec<u8>)> {
let mut reader = crate::io::file_sector_source::FileSectorSource::open(iso_path) let mut reader = crate::io::file_sector_source::FileSectorSource::open(iso_path)
.map_err(|_| Error::AacsNoKeys)?; .map_err(|_| Error::AacsNoKeys)?;
@@ -1171,10 +1170,9 @@ impl Disc {
Ok((inf, mkb)) Ok((inf, mkb))
} }
/// Same as [`Disc::read_aacs_inputs`] but reads from a live drive. Keys are /// Same as [`Disc::read_aacs_inputs`] but reads from a live drive. The
/// needed *during* scan and the ISO only exists post-rip, so the keyserver /// out-of-band Unit Key path fetches the disc's key files from the drive,
/// path fetches the disc's key files from the live drive before /// resolves a key from them however it likes, then scans with
/// [`Disc::scan`], POSTs them, then scans with
/// `ScanOptions { unit_key: Some(uk), .. }`. These files are plaintext UDF /// `ScanOptions { unit_key: Some(uk), .. }`. These files are plaintext UDF
/// metadata — no AACS handshake or keys are required to read them. /// metadata — no AACS handshake or keys are required to read them.
pub fn read_aacs_inputs_from_drive(drive: &mut Drive) -> Result<(Vec<u8>, Vec<u8>)> { pub fn read_aacs_inputs_from_drive(drive: &mut Drive) -> Result<(Vec<u8>, Vec<u8>)> {
@@ -1213,7 +1211,7 @@ impl Disc {
(None, None) (None, None)
} else if let Some(unit_key) = opts.unit_key { } else if let Some(unit_key) = opts.unit_key {
// Second key source: caller supplied the Unit Key directly // Second key source: caller supplied the Unit Key directly
// (keyserver path). Skip keydb entirely. // (external Unit Key). Skip keydb entirely.
match Self::resolve_encryption_static(&udf_fs, reader, unit_key, handshake.as_ref()) { match Self::resolve_encryption_static(&udf_fs, reader, unit_key, handshake.as_ref()) {
Ok(state) => (Some(state), None), Ok(state) => (Some(state), None),
Err(e) => (None, Some(e)), Err(e) => (None, Some(e)),
+1 -1
View File
@@ -163,7 +163,7 @@ fn validate_network_addr(addr: &str) -> io::Result<()> {
#[derive(Default)] #[derive(Default)]
pub struct InputOptions { pub struct InputOptions {
pub keydb_path: Option<String>, pub keydb_path: Option<String>,
/// Caller-supplied Unit Key (keyserver path) — the second, mutually /// Caller-supplied Unit Key (external Unit Key) — the second, mutually
/// exclusive key source. Takes precedence over `keydb_path`. /// exclusive key source. Takes precedence over `keydb_path`.
pub unit_key: Option<[u8; 16]>, pub unit_key: Option<[u8; 16]>,
pub title_index: Option<usize>, pub title_index: Option<usize>,