AACS graceful fallback: handshake optional, disc-hash-only KEYDB path

- SCSI handshake now optional: if drive doesn't support AACS layer
 (e.g. raw-mode drives where AACS feature current=0), falls back
 to disc-hash-only KEYDB lookup
- open_no_unlock(): open drive without entering raw mode
- device_path tracking on DriveSession
- Real drive test: BU40N with Civil War UHD
 - Handshake correctly fails (05/6F/01 key not present — expected)
 - Scan continues, finds AACS directory, reads Unit_Key_RO.inf
 - KEYDB lookup attempted (disc hash matching WIP)
This commit is contained in:
MattJackson
2026-04-07 11:41:34 -07:00
parent 193b571967
commit cc58ab1754
5 changed files with 83 additions and 26 deletions
+43
View File
@@ -20,6 +20,7 @@ pub struct DriveSession {
platform: Box<dyn Platform>,
pub profile: DriveProfile,
pub drive_id: DriveId,
device_path: String,
}
impl DriveSession {
@@ -64,6 +65,7 @@ impl DriveSession {
platform,
profile,
drive_id,
device_path: device.to_string_lossy().to_string(),
};
// Always unlock on open — makes all reads work immediately.
@@ -75,6 +77,46 @@ impl DriveSession {
Ok(session)
}
/// Open a drive WITHOUT unlocking (raw mode).
/// Used for AACS authentication which must happen before unlock.
pub fn open_no_unlock(device: &Path) -> Result<Self> {
let mut transport = crate::scsi::open(device)?;
let profiles = profile::load_bundled()?;
let drive_id = DriveId::from_drive(transport.as_mut())?;
let profile = profile::find_by_drive_id(&profiles, &drive_id)
.cloned()
.ok_or_else(|| Error::UnsupportedDrive {
vendor_id: drive_id.vendor_id.trim().to_string(),
product_id: drive_id.product_id.trim().to_string(),
product_revision: drive_id.product_revision.trim().to_string(),
})?;
let platform: Box<dyn Platform> = match profile.chipset {
Chipset::MediaTek => Box::new(Mt1959::new(profile.clone())),
Chipset::Renesas => {
return Err(Error::UnsupportedDrive {
vendor_id: drive_id.vendor_id.trim().to_string(),
product_id: drive_id.product_id.trim().to_string(),
product_revision: "Renesas not yet implemented".to_string(),
});
}
};
Ok(DriveSession {
scsi: transport,
platform,
profile,
drive_id,
device_path: device.to_string_lossy().to_string(),
})
}
/// Device path this session was opened on.
pub fn device_path(&self) -> &str {
&self.device_path
}
/// Open with an explicit profile (skip auto-detection).
pub fn open_with_profile(device: &Path, profile: DriveProfile) -> Result<Self> {
let mut transport = crate::scsi::open(device)?;
@@ -98,6 +140,7 @@ impl DriveSession {
platform,
profile,
drive_id,
device_path: String::new(),
})
}