AACS 2.0: full P-256 handshake, HC2 parsing, stubbed for credentials

- Full aacs2_authenticate_p256(): AGID → P-256 cert exchange → ECDSA
 signatures → ECDH bus key. Complete SCSI payload format (132-byte
 certs, 128-byte key+sig).
- Falls back: tries AACS 1.0 first, P-256 only if drive rejects v1.
- HC2 KEYDB parsing: | HC2 | HOST_PRIV_KEY 0x... | HOST_CERT 0x...
 (32-byte private key, 132-byte certificate)
- P-256 key pair generation for ephemeral handshake
- AACS 2.0 cert verification with LA public key
- Waiting on: AACS 2.0 host credentials (HC2 entry in KEYDB)
- SKB: detected (use_skb_mkb flag) but not processed — VUK from KEYDB
 still works for all discs

32 tests passing.
This commit is contained in:
MattJackson
2026-04-08 08:03:40 -07:00
parent da0eeae6a7
commit 82746ed592
2 changed files with 179 additions and 19 deletions
+28 -1
View File
@@ -133,7 +133,18 @@ impl KeyDb {
continue;
}
// Host Certificate
// Host Certificate (AACS 2.0)
if line.starts_with("| HC2") {
if let Some(ref mut hc) = db.host_cert {
if let Some((pk, cert)) = Self::parse_host_cert_v2(line) {
hc.private_key_v2 = Some(pk);
hc.certificate_v2 = Some(cert);
}
}
continue;
}
// Host Certificate (AACS 1.0)
if line.starts_with("| HC") {
db.host_cert = Self::parse_host_cert(line);
continue;
@@ -212,6 +223,22 @@ impl KeyDb {
})
}
/// Parse AACS 2.0 host cert: `| HC2 | HOST_PRIV_KEY 0x... | HOST_CERT 0x...`
fn parse_host_cert_v2(line: &str) -> Option<([u8; 32], Vec<u8>)> {
let priv_str = line.split("HOST_PRIV_KEY").nth(1)?.split('|').next()?.trim();
let cert_str = line.split("HOST_CERT").nth(1)?.split(';').next()?.split('|').next()?.trim();
let priv_bytes = parse_hex(priv_str)?;
if priv_bytes.len() != 32 { return None; }
let mut pk = [0u8; 32];
pk.copy_from_slice(&priv_bytes);
let cert = parse_hex(cert_str)?;
if cert.len() < 132 { return None; }
Some((pk, cert))
}
fn parse_disc_entry(line: &str) -> Option<DiscEntry> {
// 0x<hash> = <title> | D | <date> | M | 0x<mk> | I | 0x<id> | V | 0x<vuk> | U | <unit_keys>
let (hash_part, rest) = line.split_once(" = ")?;