mirror of
https://github.com/freemkv/freemkv-unlock.git
synced 2026-10-07 18:13:11 +00:00
freemkv-unlock 1.7.4: Hrl=off in arm_bypass recipes + version
arm_bypass_bd/arm_bypass_uhd now also Set(Hrl, off) (revocation skip) so a revoked/absent cert never trips the HRL check on a keyless bypass rip; tests updated for the new SET/verify order.
This commit is contained in:
Generated
+5
-5
@@ -104,7 +104,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "freemkv-unlock"
|
||||
version = "1.7.1"
|
||||
version = "1.7.4"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"base64",
|
||||
@@ -406,16 +406,16 @@ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
|
||||
|
||||
[[patch.unused]]
|
||||
name = "freemkv-engine"
|
||||
version = "1.7.1"
|
||||
version = "1.7.4"
|
||||
|
||||
[[patch.unused]]
|
||||
name = "freemkv-i18n"
|
||||
version = "1.7.1"
|
||||
version = "1.7.4"
|
||||
|
||||
[[patch.unused]]
|
||||
name = "freemkv-keysources"
|
||||
version = "1.7.1"
|
||||
version = "1.7.4"
|
||||
|
||||
[[patch.unused]]
|
||||
name = "libfreemkv"
|
||||
version = "1.7.1"
|
||||
version = "1.7.4"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "freemkv-unlock"
|
||||
version = "1.7.3"
|
||||
version = "1.7.4"
|
||||
edition = "2024"
|
||||
rust-version = "1.88"
|
||||
license = "MIT"
|
||||
|
||||
+16
-2
@@ -361,6 +361,7 @@ mod tests {
|
||||
// A minimal freemkv drive: IDENTITY→magic, SET updates state, GET reads it.
|
||||
struct FwDrive {
|
||||
ake: u8,
|
||||
hrl: u8,
|
||||
cdbs: Vec<Vec<u8>>,
|
||||
}
|
||||
impl ScsiTransport for FwDrive {
|
||||
@@ -382,12 +383,21 @@ mod tests {
|
||||
} else if cdb[CDB_VERB] == Verb::Set as u8 && cdb[CDB_FEATURE] == Feature::Ake as u8
|
||||
{
|
||||
self.ake = cdb[CDB_STATE];
|
||||
} else if cdb[CDB_VERB] == Verb::Set as u8 && cdb[CDB_FEATURE] == Feature::Hrl as u8
|
||||
{
|
||||
self.hrl = cdb[CDB_STATE];
|
||||
} else if cdb[CDB_VERB] == Verb::Get as u8
|
||||
&& cdb[CDB_FEATURE] == Feature::Ake as u8
|
||||
&& !data.is_empty()
|
||||
{
|
||||
data[0] = self.ake;
|
||||
n = 1;
|
||||
} else if cdb[CDB_VERB] == Verb::Get as u8
|
||||
&& cdb[CDB_FEATURE] == Feature::Hrl as u8
|
||||
&& !data.is_empty()
|
||||
{
|
||||
data[0] = self.hrl;
|
||||
n = 1;
|
||||
}
|
||||
Ok(crate::scsi::ScsiResult {
|
||||
status: 0,
|
||||
@@ -398,15 +408,19 @@ mod tests {
|
||||
}
|
||||
let mut t = FwDrive {
|
||||
ake: STATE_PASSTHROUGH,
|
||||
hrl: STATE_PASSTHROUGH,
|
||||
cdbs: Vec::new(),
|
||||
};
|
||||
let u = AacsUnlocker::new(vec![host_cert()]).arm_before_unlock(ArmRecipe::BypassBd);
|
||||
u.maybe_arm(&mut t).expect("armed");
|
||||
assert_eq!(t.hrl, STATE_OFF, "the recipe skipped revocation (Hrl=off)");
|
||||
assert_eq!(t.ake, STATE_OFF, "the recipe nulled the AKE (Ake=off)");
|
||||
// IDENTITY, then Set(Ake,off), then a verifying Get(Ake).
|
||||
// IDENTITY, then Set(Hrl,off)+verify, then Set(Ake,off)+verify.
|
||||
assert_eq!(t.cdbs[0][CDB_VERB], Verb::Identity as u8);
|
||||
assert_eq!(t.cdbs[1], build_set_cdb(Feature::Ake, STATE_OFF));
|
||||
assert_eq!(t.cdbs[1], build_set_cdb(Feature::Hrl, STATE_OFF));
|
||||
assert_eq!(t.cdbs[2][CDB_VERB], Verb::Get as u8);
|
||||
assert_eq!(t.cdbs[3], build_set_cdb(Feature::Ake, STATE_OFF));
|
||||
assert_eq!(t.cdbs[4][CDB_VERB], Verb::Get as u8);
|
||||
}
|
||||
|
||||
/// With no host certs there is nothing to authenticate with → `Ok(false)`,
|
||||
|
||||
+7
-2
@@ -698,17 +698,22 @@ impl<'a> FirmwareControl<'a> {
|
||||
/// **arm_bypass_bd** — full-bypass Blu-ray rip (NO host cert needed).
|
||||
///
|
||||
/// Sets: `Ake = null` (drive acts pre-authenticated, so a bare VID read
|
||||
/// returns the volume ID with no cert and no AKE). Rips: BD with no cert.
|
||||
/// returns the volume ID with no cert and no AKE) and `Hrl = skip`
|
||||
/// (revocation off, so a revoked/absent cert never trips the HRL check).
|
||||
/// Rips: BD with no cert.
|
||||
pub fn arm_bypass_bd(&mut self) -> Result<()> {
|
||||
self.set_verify(Feature::Hrl, STATE_OFF)?;
|
||||
self.set_verify(Feature::Ake, STATE_OFF)
|
||||
}
|
||||
|
||||
/// **arm_bypass_uhd** — full-bypass UHD rip (NO host cert needed).
|
||||
///
|
||||
/// Sets: `Uhd = on` (engage the UHD disc), `Ake = null` (skip the
|
||||
/// handshake), `Bus = off` (content de-bussed). Rips: UHD with no cert.
|
||||
/// handshake), `Bus = off` (content de-bussed), and `Hrl = skip`
|
||||
/// (revocation off). Rips: UHD with no cert.
|
||||
pub fn arm_bypass_uhd(&mut self) -> Result<()> {
|
||||
self.set_verify(Feature::Uhd, STATE_ON)?;
|
||||
self.set_verify(Feature::Hrl, STATE_OFF)?;
|
||||
self.set_verify(Feature::Ake, STATE_OFF)?;
|
||||
self.set_verify(Feature::Bus, STATE_OFF)
|
||||
}
|
||||
|
||||
@@ -489,8 +489,12 @@ fn arm_bypass_bd_nulls_ake() {
|
||||
let mut fw = FirmwareControl::new(&mut m);
|
||||
fw.arm_bypass_bd().expect("armed");
|
||||
}
|
||||
assert_eq!(m.cdbs[0], build_set_cdb(Feature::Ake, STATE_OFF));
|
||||
assert_eq!(m.cdbs[1], build_get_cdb(Feature::Ake));
|
||||
// Hrl=off (revocation skip) is set+verified FIRST, then Ake=null.
|
||||
assert_eq!(m.cdbs[0], build_set_cdb(Feature::Hrl, STATE_OFF));
|
||||
assert_eq!(m.cdbs[1], build_get_cdb(Feature::Hrl));
|
||||
assert_eq!(m.cdbs[2], build_set_cdb(Feature::Ake, STATE_OFF));
|
||||
assert_eq!(m.cdbs[3], build_get_cdb(Feature::Ake));
|
||||
assert_eq!(m.states.hrl, STATE_OFF);
|
||||
assert_eq!(m.states.ake, STATE_OFF);
|
||||
}
|
||||
|
||||
@@ -501,10 +505,13 @@ fn arm_bypass_uhd_sets_uhd_ake_bus() {
|
||||
let mut fw = FirmwareControl::new(&mut m);
|
||||
fw.arm_bypass_uhd().expect("armed");
|
||||
}
|
||||
// Recipe order: Uhd=on, Hrl=off, Ake=null, Bus=off (each SET then verifying GET).
|
||||
assert_eq!(m.cdbs[0], build_set_cdb(Feature::Uhd, STATE_ON));
|
||||
assert_eq!(m.cdbs[2], build_set_cdb(Feature::Ake, STATE_OFF));
|
||||
assert_eq!(m.cdbs[4], build_set_cdb(Feature::Bus, STATE_OFF));
|
||||
assert_eq!(m.cdbs[2], build_set_cdb(Feature::Hrl, STATE_OFF));
|
||||
assert_eq!(m.cdbs[4], build_set_cdb(Feature::Ake, STATE_OFF));
|
||||
assert_eq!(m.cdbs[6], build_set_cdb(Feature::Bus, STATE_OFF));
|
||||
assert_eq!(m.states.uhd, STATE_ON);
|
||||
assert_eq!(m.states.hrl, STATE_OFF);
|
||||
assert_eq!(m.states.ake, STATE_OFF);
|
||||
assert_eq!(m.states.bus, STATE_OFF);
|
||||
}
|
||||
@@ -563,10 +570,11 @@ fn set_verify_reports_mismatch() {
|
||||
let mut d = StuckDrive;
|
||||
let mut fw = FirmwareControl::new(&mut d);
|
||||
let err = fw.arm_bypass_bd().unwrap_err();
|
||||
// arm_bypass_bd now verifies Hrl=off FIRST, so the stuck drive trips on Hrl.
|
||||
assert_eq!(
|
||||
err,
|
||||
FirmwareError::VerifyFailed {
|
||||
feature: Feature::Ake,
|
||||
feature: Feature::Hrl,
|
||||
wanted: STATE_OFF,
|
||||
got: STATE_PASSTHROUGH,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user