aacs: handshake primitives operate on &mut dyn ScsiTransport
The AACS cert-auth primitives (aacs_authenticate, the AACS 2.0 P-256 variants, read_volume_id, read_data_keys) and their scsi_read/scsi_write helpers touched the drive ONLY through Drive::scsi_execute — a pure pass-through to the transport. Thread &mut dyn ScsiTransport instead of &mut Drive so these primitives are transport-level, matching the firmware Unlocker seam (which hands out &mut dyn ScsiTransport for testability). Pure mechanical signature change, no logic change; the cert orchestrator (do_handshake_cert) keeps &mut Drive for the OEM-VID shortcut and passes session.scsi_mut() into the primitives. Step toward making the cert handshake a uniform registry unlocker.
This commit is contained in:
+13
-11
@@ -18,9 +18,8 @@
|
|||||||
//! - AACS 2.0: drives accept AACS 1.0 host certs for backward compatibility
|
//! - AACS 2.0: drives accept AACS 1.0 host certs for backward compatibility
|
||||||
//! (full P-256/SHA-256 AACS 2.0 handshake prepared but rarely needed)
|
//! (full P-256/SHA-256 AACS 2.0 handshake prepared but rarely needed)
|
||||||
|
|
||||||
use crate::drive::Drive;
|
|
||||||
use crate::error::{Error, Result};
|
use crate::error::{Error, Result};
|
||||||
use crate::scsi::DataDirection;
|
use crate::scsi::{DataDirection, ScsiTransport};
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use num_traits::{One, Zero};
|
use num_traits::{One, Zero};
|
||||||
use sha1::{Digest, Sha1};
|
use sha1::{Digest, Sha1};
|
||||||
@@ -45,16 +44,16 @@ fn handshake_err(err: Error, fallback: Error) -> Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a SCSI command that reads data from the device.
|
/// Execute a SCSI command that reads data from the device.
|
||||||
fn scsi_read(session: &mut Drive, cdb: &[u8], len: usize) -> Result<Vec<u8>> {
|
fn scsi_read(session: &mut dyn ScsiTransport, cdb: &[u8], len: usize) -> Result<Vec<u8>> {
|
||||||
let mut buf = vec![0u8; len];
|
let mut buf = vec![0u8; len];
|
||||||
session.scsi_execute(cdb, DataDirection::FromDevice, &mut buf, 5_000)?;
|
session.execute(cdb, DataDirection::FromDevice, &mut buf, 5_000)?;
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a SCSI command that writes data to the device.
|
/// Execute a SCSI command that writes data to the device.
|
||||||
fn scsi_write(session: &mut Drive, cdb: &[u8], data: &[u8]) -> Result<()> {
|
fn scsi_write(session: &mut dyn ScsiTransport, cdb: &[u8], data: &[u8]) -> Result<()> {
|
||||||
let mut buf = data.to_vec();
|
let mut buf = data.to_vec();
|
||||||
session.scsi_execute(cdb, DataDirection::ToDevice, &mut buf, 5_000)?;
|
session.execute(cdb, DataDirection::ToDevice, &mut buf, 5_000)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -881,7 +880,7 @@ impl std::fmt::Debug for AacsAuth {
|
|||||||
/// Requires a host private key (20 bytes) and host certificate (92 bytes)
|
/// Requires a host private key (20 bytes) and host certificate (92 bytes)
|
||||||
/// from the KEYDB.cfg HC entry.
|
/// from the KEYDB.cfg HC entry.
|
||||||
pub fn aacs_authenticate(
|
pub fn aacs_authenticate(
|
||||||
session: &mut Drive,
|
session: &mut dyn ScsiTransport,
|
||||||
host_priv_key: &[u8; 20],
|
host_priv_key: &[u8; 20],
|
||||||
host_cert: &[u8],
|
host_cert: &[u8],
|
||||||
) -> Result<AacsAuth> {
|
) -> Result<AacsAuth> {
|
||||||
@@ -1018,7 +1017,7 @@ pub fn aacs_authenticate(
|
|||||||
/// Falls back to aacs_authenticate (AACS 1.0) if AACS 2.0 host credentials
|
/// Falls back to aacs_authenticate (AACS 1.0) if AACS 2.0 host credentials
|
||||||
/// are not available.
|
/// are not available.
|
||||||
pub fn aacs2_authenticate(
|
pub fn aacs2_authenticate(
|
||||||
session: &mut Drive,
|
session: &mut dyn ScsiTransport,
|
||||||
host_priv_key_v1: &[u8; 20],
|
host_priv_key_v1: &[u8; 20],
|
||||||
host_cert_v1: &[u8],
|
host_cert_v1: &[u8],
|
||||||
host_priv_key_v2: Option<&[u8; 32]>,
|
host_priv_key_v2: Option<&[u8; 32]>,
|
||||||
@@ -1044,7 +1043,7 @@ pub fn aacs2_authenticate(
|
|||||||
/// Native AACS 2.0 handshake using P-256/SHA-256.
|
/// Native AACS 2.0 handshake using P-256/SHA-256.
|
||||||
/// Same SCSI protocol, larger payloads (32-byte keys, 132-byte certs).
|
/// Same SCSI protocol, larger payloads (32-byte keys, 132-byte certs).
|
||||||
fn aacs2_authenticate_p256(
|
fn aacs2_authenticate_p256(
|
||||||
session: &mut Drive,
|
session: &mut dyn ScsiTransport,
|
||||||
host_priv_key: &[u8; 32],
|
host_priv_key: &[u8; 32],
|
||||||
host_cert: &[u8],
|
host_cert: &[u8],
|
||||||
) -> Result<AacsAuth> {
|
) -> Result<AacsAuth> {
|
||||||
@@ -1169,7 +1168,7 @@ fn aacs2_authenticate_p256(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read Volume ID after successful authentication.
|
/// Read Volume ID after successful authentication.
|
||||||
pub fn read_volume_id(session: &mut Drive, auth: &mut AacsAuth) -> Result<[u8; 16]> {
|
pub fn read_volume_id(session: &mut dyn ScsiTransport, auth: &mut AacsAuth) -> Result<[u8; 16]> {
|
||||||
// REPORT DISC STRUCTURE format 0x80
|
// REPORT DISC STRUCTURE format 0x80
|
||||||
let cdb = cdb_report_disc_structure(auth.agid, 0x80, 36);
|
let cdb = cdb_report_disc_structure(auth.agid, 0x80, 36);
|
||||||
let response =
|
let response =
|
||||||
@@ -1191,7 +1190,10 @@ pub fn read_volume_id(session: &mut Drive, auth: &mut AacsAuth) -> Result<[u8; 1
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read data keys after successful authentication (for AACS 2.0 bus encryption).
|
/// Read data keys after successful authentication (for AACS 2.0 bus encryption).
|
||||||
pub fn read_data_keys(session: &mut Drive, auth: &mut AacsAuth) -> Result<([u8; 16], [u8; 16])> {
|
pub fn read_data_keys(
|
||||||
|
session: &mut dyn ScsiTransport,
|
||||||
|
auth: &mut AacsAuth,
|
||||||
|
) -> Result<([u8; 16], [u8; 16])> {
|
||||||
// REPORT DISC STRUCTURE format 0x84
|
// REPORT DISC STRUCTURE format 0x84
|
||||||
let cdb = cdb_report_disc_structure(auth.agid, 0x84, 36);
|
let cdb = cdb_report_disc_structure(auth.agid, 0x84, 36);
|
||||||
let response =
|
let response =
|
||||||
|
|||||||
+9
-3
@@ -118,9 +118,14 @@ impl AacsCertUnlocker<'_> {
|
|||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
std::thread::sleep(std::time::Duration::from_millis(PER_CERT_BACKOFF_MS));
|
std::thread::sleep(std::time::Duration::from_millis(PER_CERT_BACKOFF_MS));
|
||||||
}
|
}
|
||||||
match aacs::handshake::aacs_authenticate(session, &hc.private_key, &hc.certificate) {
|
match aacs::handshake::aacs_authenticate(
|
||||||
|
session.scsi_mut(),
|
||||||
|
&hc.private_key,
|
||||||
|
&hc.certificate,
|
||||||
|
) {
|
||||||
Ok(mut auth) => {
|
Ok(mut auth) => {
|
||||||
let volume_id = match aacs::handshake::read_volume_id(session, &mut auth) {
|
let volume_id =
|
||||||
|
match aacs::handshake::read_volume_id(session.scsi_mut(), &mut auth) {
|
||||||
Ok(vid) => vid,
|
Ok(vid) => vid,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
@@ -134,7 +139,8 @@ impl AacsCertUnlocker<'_> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (read_data_key, read_data_key_err) = match aacs::handshake::read_data_keys(
|
let (read_data_key, read_data_key_err) = match aacs::handshake::read_data_keys(
|
||||||
session, &mut auth,
|
session.scsi_mut(),
|
||||||
|
&mut auth,
|
||||||
) {
|
) {
|
||||||
Ok((rdk, _)) => (Some(rdk), None),
|
Ok((rdk, _)) => (Some(rdk), None),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user