aacs: relocate the AACS cert handshake into freemkv-unlock

Stage 2: the AACS host-certificate handshake (the AKE + bus-key derivation +
P-160/P-256 EC crypto, ~2050 lines) moves out of libfreemkv into the
self-contained src/aacs module, with its own error type (the Aacs* failure
points + structured ScsiError) and an aes_ecb_decrypt helper. AacsCert impls
crate::Unlocker — matches DiscKind::Aacs, runs run_cert_handshake against the
host certs the consumer passes via UnlockCtx, and returns Unlocked { vid,
bus_key }. collect_host_certs stays in libfreemkv (it reads keysources). The
SCSI contract gains ScsiSense + the AACS/REPORT-KEY opcodes. libfreemkv is
untouched (still green); it rewires onto this in stage 4.

72 tests pass (the handshake brought its full EC-crypto test suite).
This commit is contained in:
Matthew Jackson
2026-06-29 19:33:07 -07:00
parent 0e943c3792
commit 22130bfe12
6 changed files with 2280 additions and 6 deletions
+8 -2
View File
@@ -12,8 +12,8 @@
pub mod scsi;
mod aacs;
mod ld;
// mod aacs; // stage 2 — AACS host-certificate handshake
// mod css; // stage 3 — CSS bus-auth
use scsi::ScsiTransport;
@@ -41,8 +41,14 @@ pub enum DiscKind {
/// these from its key sources and passes them in).
#[derive(Debug, Clone)]
pub struct HostCert {
/// AACS 1.0 host private key (20 bytes).
pub private_key: [u8; 20],
/// AACS 1.0 host certificate (92 bytes).
pub certificate: Vec<u8>,
/// AACS 2.0 host private key (P-256, 32 bytes). `None` for AACS 1.0 only.
pub private_key_v2: Option<[u8; 32]>,
/// AACS 2.0 host certificate (type 0x11). `None` for AACS 1.0 only.
pub certificate_v2: Option<Vec<u8>>,
}
/// Context handed to an unlocker: drive identity, disc kind, and (for the cert
@@ -114,7 +120,7 @@ pub trait Unlocker: Send + Sync {
pub fn all_unlockers() -> Vec<Box<dyn Unlocker>> {
vec![
Box::new(ld::LibreDrive::new()),
// Box::new(aacs::AacsCert::new()), // stage 2
Box::new(aacs::AacsCert::new()),
// Box::new(css::Css::new()), // stage 3
]
}