aacs: source OEM host certs from keysource layer
Complete the OEM/AACS cert baseline so host certs are a KeySource output,
never compiled in. With an unlocker present the OEM route is unused
(unlocker_read_volume_id short-circuits); without one, the cert handshake
runs when a keysource supplies a host cert and fails gracefully when none
does.
- KeySource trait gains host_certs() (default empty), reusing the existing
aacs::HostCert type. A source holds certs as its second kind of AACS
material alongside decryption keys.
- ScanOptions gains key_sources so the handshake can collect certs across
the app's keysource layer, unioned with DriveCredentials.
- do_handshake_cert collects certs via collect_host_certs (credentials +
every key source). Zero certs from any source now returns the new
graceful Error::AacsNoHostCert (code 7024, sentinel <no host cert>)
instead of silently skipping; resolution still falls back to the
path-1 disc-hash -> VUK lookup, which drops the error on a hit.
- error.rs: add E_AACS_NO_HOST_CERT / Error::AacsNoHostCert, wired into
code(), Display, and the round-trip + sentinel tests.
HandshakeResult { volume_id, read_data_key } unchanged: the cert path
still yields both the VID and the bus key.
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
//! out of the library while all key *mechanism* (the AACS derivation chain)
|
||||
//! stays in it.
|
||||
|
||||
use crate::aacs::HostCert;
|
||||
use crate::disc::Key;
|
||||
|
||||
/// The public AACS inputs a key source needs to look a disc up. Captured at
|
||||
@@ -92,6 +93,25 @@ pub trait KeySource {
|
||||
fn errored(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// The AACS host certificate(s) this source can supply for the live-drive
|
||||
/// SCSI mutual-auth handshake (the OEM/AACS baseline route). A host cert is
|
||||
/// the *second* kind of AACS material a source may hold, distinct from the
|
||||
/// decryption keys handed out by [`KeySource::next_key`]: it unlocks the
|
||||
/// authenticated bus so the drive will report the Volume ID and bus key,
|
||||
/// whereas the keys decrypt content once the disc is read.
|
||||
///
|
||||
/// Returned, never compiled in: a host cert is **perishable** — it can be
|
||||
/// revoked on a given drive's Host Revocation List (carried forward by newer
|
||||
/// discs' MKBs), so it must be rotatable, hence served by a source rather
|
||||
/// than baked into the binary. A source that holds no cert (a mapfile, or an
|
||||
/// online service whose cert-serving isn't yet designed) returns the empty
|
||||
/// vec — the default. The handshake collects across every source and tries
|
||||
/// each candidate; with no candidate from any source the OEM route fails
|
||||
/// gracefully ([`crate::Error::AacsNoHostCert`]), it never panics.
|
||||
fn host_certs(&self) -> Vec<HostCert> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user