css: relocate the CSS bus-auth into freemkv-unlock; all 3 unlockers wired

Stage 3: the CSS bus-authentication (the challenge-response that sets the
drive's ASF=1 to unlock scrambled-sector reads, plus crypt_key + the CSS
tables) moves out of libfreemkv into the self-contained src/css module, with
its own error type. CssUnlocker impls crate::Unlocker — matches DiscKind::Css,
self-guards against a non-DVD profile, runs the bus-auth, and returns an empty
Unlocked (CSS yields no VID/bus key; the keyless Stevenson descramble stays in
libfreemkv). The keyless descramble (lfsr/stevenson) is NOT moved — that's
content decryption, the consumer's job.

all_unlockers() now returns [LibreDrive, AacsCert, CssUnlocker] — the entire
unlock layer is built. libfreemkv rewires onto it in stage 4. 89 tests pass.
This commit is contained in:
Matthew Jackson
2026-06-29 19:36:28 -07:00
parent 22130bfe12
commit 02d50664ff
4 changed files with 1048 additions and 2 deletions
+41
View File
@@ -0,0 +1,41 @@
//! css's internal error for the CSS bus-auth code. Distinct from
//! [`crate::UnlockError`] (the outcome the consumer sees).
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub enum Error {
/// The CSS bus-authentication challenge-response failed.
CssAuthFailed,
/// A SCSI transport-layer fault.
Scsi(crate::scsi::ScsiError),
}
impl Error {
/// Stable numeric code (logged). Values are local to this crate.
pub fn code(&self) -> u16 {
match self {
Error::CssAuthFailed => 7201,
Error::Scsi(_) => 7299,
}
}
}
impl From<crate::scsi::ScsiError> for Error {
fn from(e: crate::scsi::ScsiError) -> Self {
Error::Scsi(e)
}
}
/// CSS bus-auth either enables scrambled reads or it doesn't — any failure means
/// "this unlocker didn't apply" (a transport fault still surfaces as Transport).
impl From<Error> for crate::UnlockError {
fn from(e: Error) -> Self {
match e {
Error::Scsi(s) if s.status == crate::scsi::SCSI_STATUS_TRANSPORT_FAILURE => {
crate::UnlockError::Transport
}
_ => crate::UnlockError::NotApplicable,
}
}
}
+1004
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -13,8 +13,8 @@
pub mod scsi;
mod aacs;
mod css;
mod ld;
// mod css; // stage 3 — CSS bus-auth
use scsi::ScsiTransport;
@@ -121,6 +121,6 @@ pub fn all_unlockers() -> Vec<Box<dyn Unlocker>> {
vec![
Box::new(ld::LibreDrive::new()),
Box::new(aacs::AacsCert::new()),
// Box::new(css::Css::new()), // stage 3
Box::new(css::CssUnlocker::new()),
]
}
+1
View File
@@ -74,6 +74,7 @@ pub(crate) const SCSI_SET_CD_SPEED: u8 = 0xBB;
pub(crate) const SCSI_SEND_KEY: u8 = 0xA3;
pub(crate) const SCSI_REPORT_KEY: u8 = 0xA4;
pub(crate) const SCSI_READ_DISC_STRUCTURE: u8 = 0xAD;
pub(crate) const SCSI_GET_CONFIGURATION: u8 = 0x46;
/// AACS key class selector used in REPORT/SEND KEY CDBs.
pub(crate) const AACS_KEY_CLASS: u8 = 0x02;