Commit Graph
63 Commits
Author SHA1 Message Date
Matthew Jackson ce69f319d1 docs: 1.3.0 changelog 2026-07-10 08:19:22 -07:00
Matthew Jackson f4a3adf67c release: bump to 1.3.0 2026-07-08 14:48:50 -07:00
Matthew Jackson 745d9c0084 keydb: round-trip AACS 2.0 host certs; tighten entry validation
- to_keydb_cfg emits the sibling `| HC2 |` line (AACS 2.0 host cert),
  the inverse of parse_host_cert_v2, so a round-trip never silently
  drops v2 host certs.
- save-validation mirrors the parser's real disc-entry rule exactly: a
  `0x` line counts as an entry only if it also contains ` = `, so
  validating + persisting content that parses to zero usable entries
  (e.g. a stray `0xDEADBEEF` line) can no longer succeed.
- disc-entry title is kept verbatim (parens and all) on parse, matching
  the emit path so it round-trips.
2026-07-08 14:45:25 -07:00
Matthew Jackson b152710f53 Bump to 1.2.3 2026-07-07 16:36:25 -07:00
Matthew Jackson 3bc8969c5f keydb/online: resolve off aacs::derive + types, drop boil wrappers
leak-guard / leak-guard (push) Failing after 5s
libfreemkv deleted the aacs::boil veneer, so switch the resolve path to the
raw primitives: derive_media_key_from_{pk,dk}, derive_vuk, decrypt_unit_key
from aacs::derive, and the newtypes from aacs::types. Add a local uks_from_vuk
helper composing decrypt_unit_key. No behaviour change; fmt/clippy/test green
on Rust 1.86.
2026-07-05 12:09:50 -07:00
Matthew Jackson ff63a4dfa9 v1.2.2: bump version (unified release) 2026-07-03 20:50:20 -07:00
Matthew Jackson f93dddf40c keydb: adopt corrected mk_from_dk (2-arg), reviving the DK->MK fallback
libfreemkv's AACS work changes mk_from_dk from (dk, mkb, vid) to (dk, mkb) —
the VID enters at the VUK step, not the MK step. Adopt the 2-arg call so the DK
pool is tried unconditionally (no longer gated on a VID being present), matching
libfreemkv. Without this keysources fails to compile against the new libfreemkv.
(Equivalent to the stranded b80d4cb; applied directly since that branch had
diverged surrounding context.)
2026-07-03 20:36:50 -07:00
Matthew Jackson c07467c84e v1.2.1: bump version (unified release) 2026-07-01 19:08:59 -07:00
Matthew Jackson 290fc6aafb v1.2.1: bump version 2026-07-01 17:30:25 -07:00
Matthew Jackson 2cc7c30fa3 Cargo: publish = false + git-pin libfreemkv (off crates.io)
keysources deps libfreemkv, now git-only, so keysources follows it off
crates.io. A committed [patch.crates-io] redirects the bare libfreemkv version
req to the git tag (local dev overrides to a path via the gitignored config).
2026-06-29 21:04:05 -07:00
Matthew Jackson a5c492f4c2 docs: 1.2.0 changelog date → 2026-06-29 (release prep) 2026-06-29 09:57:29 -07:00
Matthew Jackson 408ebc493c docs: 1.2.0 changelog — drop pre-1.1.0 carryover entries
The 'KeydbSource owns save+update' (Added) and 'Processing-Key
decryption restored' (Fixed) entries were stale carryover from the
never-released 1.1.0-beta.1; that code shipped in v1.1.0 (zero diff in
v1.1.0..HEAD). The 1.2.0 entry now lists only the real 1.2.0 changes
(hex unification, DiscInputs version stride, MKB cap).
2026-06-29 01:21:46 -07:00
Matthew Jackson f32f0bc282 v1.2.0: bump version + reconcile CHANGELOG to [1.2.0] 2026-06-28 23:34:19 -07:00
Matthew Jackson 34e2d3a0e8 1.2.0: route online/keydb hex parsing through libfreemkv::hex (one parser) 2026-06-28 22:12:07 -07:00
Matthew Jackson bbbbec8844 1.1.1: DiscInputs gains version; tests pull stride from inputs.version 2026-06-28 21:45:58 -07:00
Matthew Jackson 4eb53b0c93 1.1.1: align online MKB cap with libfreemkv read cap (64 MiB) + log over-cap
The online source dropped any MKB over 10 MiB while libfreemkv's reader
captures up to 64 MiB — an MKB in that band was silently un-forwardable
(no key, no surfaced cause). Match the cap and log when it is exceeded.
2026-06-28 21:12:57 -07:00
Matthew Jackson 567e5c7891 v1.1.0: bump version (unified release) 2026-06-28 18:19:57 -07:00
Matthew Jackson 334ef968c7 keydb: public-crate hygiene — scrub internal tool name from comments, synthetic test disc hash 2026-06-28 16:49:16 -07:00
Matthew Jackson e2880dd8f8 keydb: union stored UKs + VUK/MK-derived unit keys (dedup by value)
unit_keys_from now loads all stored unit keys AND the VUK/MK-derived ones, deduping by key value instead of first-hit, so a disc with partial stored UKs plus a VUK yields every declared CPS unit key. Plus keydb.cfg format round-trip (to_keydb_cfg inverse of parse).
2026-06-28 15:06:24 -07:00
Matthew Jackson ed62626922 keydb_format: faithful verbatim titles + tag-letter field fix + real-data idempotence test
leak-guard / leak-guard (push) Failing after 5s
Found via a parse->serialize->parse->serialize byte-identical check over the full
182,535-disc OEM keydb:
- Title was reduced to a parenthesised substring, truncating real titles
  ("Lawrence of Arabia (Restored Version) - Disc 2 - 4K Ultra HD" -> "Restored
  Version"). Keep the title VERBATIM (faithful copy); display prettification is a
  separate layer.
- A disc titled exactly "M" (`= M | M | 0x...`) had its title eaten as the M
  field tag, dropping the real media key. Field scan now skips parts[0] (always
  the title), so a title that is a tag letter (M/I/V/U/D) can't shadow a field.
- Add to_keydb_cfg_is_idempotent_on_real_keydb (KEYDB_PATH-gated): proves parse
  is lossless on its own output and the serializer is deterministic.
2026-06-27 15:58:30 -07:00
Matthew Jackson d638296e01 keydb_format: add to_keydb_cfg serializer (inverse of parse); rename DiscEntry.disc_id -> vid
Central round-trippable codec: parse + to_keydb_cfg in one place.
Emits HC, DK, PK, then disc entries sorted by hash. Round-trip test
(parse -> serialize -> re-parse) covers HC/DK/PK/disc. disc_id -> vid
names the field for what it is (the I-field volume ID).
2026-06-27 14:42:58 -07:00
Matthew Jackson 880830e262 keysources: expose the keydb.cfg parser (pub keydb_format / KeyDb, DiscEntry)
leak-guard / leak-guard (push) Failing after 20s
Make the parser public — parsing a keydb is not secret (freemkv uses it, and so
do tools that build a per-disc registry from it, e.g. a Volume-ID index). Purely
additive: a private module in this public crate becomes nameable; no behaviour
change, nothing removed.
2026-06-26 21:07:56 -07:00
Matthew Jackson 17fcf6d8f9 KeydbSource owns keydb save + update
Move the keydb save/validation/atomic-write path out of libfreemkv onto
KeydbSource. New KeydbSource::save(bytes) validates + decompresses (zip /
gz / plain, decompressed-size capped) and crash-safely writes to the
source's OWN path (sibling-temp + fsync + rename + parent-dir fsync) —
not a hardcoded default, so the caller chooses the destination.
KeydbSource::update(fetch, url) calls an INJECTED fetch closure then
save, keeping this crate transport-agnostic on the update path (the app
supplies its own TLS / SSRF-guarded transport). UpdateResult moves here
and is re-exported. Add flate2 + zip (already in the resolved graph via
libfreemkv) for decompression; no new HTTP stack.
2026-06-26 17:34:03 -07:00
Matthew Jackson 946632d9fb Restore AACS PK key-processing path in keysources
unit_keys_from now resolves the Media Key in order: stored per-disc MK
-> keydb Processing Key pool (mk_from_pk vs this disc's own MKB) ->
device-key pool (mk_from_dk), then MK+VID -> VUK -> UK. MK/VUK entries
still honored directly; cross-disc MK-pool brute stays retired. Fixes the
factually-wrong justifying comment + adds PK-pool KATs.
2026-06-26 17:03:58 -07:00
Matthew Jackson 6805ad22d4 AACS: own keydb parser + 100% parse + get_uk derivation
- Relocate keydb.cfg parser into keydb_format.rs (libfreemkv no longer knows
  keydb); add 100% parse (mkb_version/volume_size/is_uhd, revoked_at_mkb) +
  helper API (get_uk/get_uks/get_vid/host_certs(mkb)).
- KeydbSource/OnlineSource/MultiSource -> get_uk(ctx); MultiSource host_certs
  union; KAT-proven derivation parity. NumberedUnitKey alias. clippy clean.
2026-06-26 12:19:24 -07:00
matthew d1a4ec9a3f ci: add CI workflow (fmt + clippy -D warnings + test on Rust 1.86)
The crate previously had only leak-guard.yml and release.yml, so its ~42
tests never ran on push/PR — only on tag. Mirror the sibling crates'
ci.yml (lint + test jobs, dtolnay/rust-toolchain@1.86.0, rust-cache).
No --locked: this library does not track Cargo.lock (release.yml notes
--locked would fail on a fresh runner).
2026-06-25 17:58:30 -07:00
Matthew Jackson 8e166903cc freemkv-keysources: fixture-based integration tests for key sources
Add tests/key_sources.rs exercising the published KeySource impls
end-to-end over real fixture files and the libfreemkv parsers:

- KeydbSource: disc-hash lookup from a real keydb.cfg (VUK hit ranks
  ahead of the universal DK pool), hash miss yields only the pool,
  missing file is silent/not errored, label + needs_samples, and
  host-cert serving from a | HC | row (inherent and trait paths).
- paths: exe-local search list, default == search head, existing path
  reflects on-disk state (local-only, no OS fallback).
- MapfileSource: persisted # freemkv-uk: keys read back as a terminal
  Key::Unit, one-shot exhaustion, missing/keyless mapfile offers nothing.
- OnlineSource: unconfigured no-op (no network), one-shot latch,
  metadata, and validate_keyserver_url scheme/SSRF gating.
- MultiSource: caller-supplied order/precedence (and its reverse),
  empty-source skip, needs_samples/errored OR-aggregation, nesting, and
  a real keydb-then-mapfile precedence chain over fixtures.
2026-06-24 23:33:00 -07:00
Matthew Jackson 699a2872fb v1.0.0-rc.5.3: bump version (unified release) 2026-06-24 21:55:08 -07:00
Matthew Jackson ed744e071f freemkv-keysources: keydb search is local to the executable
keydb_search_paths() returns exactly [<exe dir>/keydb.cfg] (or empty if
current_exe is unavailable) — no %APPDATA%/.config/XDG lookup. Matches
libfreemkv::keydb::default_path.
2026-06-24 20:46:31 -07:00
Matthew Jackson 2d0d0e3966 v1.0.0-rc.5.2: bump version (unified release) 2026-06-24 17:19:48 -07:00
Matthew Jackson 91b95e15cf freemkv-keysources: pure key lookup
Move the encrypted sample reader and the key-resolution loop into libfreemkv
(they read the disc and validate keys — decryption mechanism, not lookup). A
key source now only looks a key up and hands it back.
2026-06-24 15:40:50 -07:00
Matthew Jackson a4d94d4ce3 v1.0.0-rc.5.1: bump version (unified release) 2026-06-24 14:43:34 -07:00
Matthew Jackson 1976416b14 Add Contributor Covenant v2.1 Code of Conduct 2026-06-24 10:44:59 -07:00
Matthew Jackson 2b025ab5fe v1.0.0-rc.5: bump version (unified release) 2026-06-24 10:35:11 -07:00
Matthew Jackson cced7818d2 v1.0.0-rc.4.3: bump version (unified release) 2026-06-23 15:53:02 -07:00
Matthew Jackson c247f02894 v1.0.0-rc.4.2: bump version (unified release) 2026-06-23 12:41:44 -07:00
Matthew Jackson a35f3cf84a v1.0.0-rc.4.1: bump version (unified release) 2026-06-23 10:46:48 -07:00
Matthew Jackson 9ada82a415 ci: cache Rust builds with Swatinem/rust-cache to speed up release + CI 2026-06-23 10:01:37 -07:00
Matthew Jackson 26f4c864b5 v1.0.0-rc.4: bump version (unified release) 2026-06-23 09:46:59 -07:00
Matthew Jackson a287e165bd keysources: label() on keydb/online sources; neutral path in the XDG test 2026-06-23 09:09:06 -07:00
Matthew Jackson 7982d16225 ci: fast-release — verify Cargo.lock libfreemkv resolves to the release git tag 2026-06-23 08:20:51 -07:00
Matthew Jackson a8be43ea69 keydb: require content samples so per-disc UK entries are ciphertext-validated
A keydb can hand out a per-disc terminal Key::Unit (a UK entry keyed on
disc_hash). Unlike a derived key (Device/Processing/Media/Volume), a
terminal UK is applied as-is by Disc::decrypt_with: it is NOT re-derived
through the MKB-verified AACS resolver, so a UK entry whose hash matches
the disc but whose key bytes are wrong is only disproved by descrambling
real ciphertext.

KeydbSource inherited the default needs_samples() == false, so on the
autorip auto-resume / mux-worker path (which samples units only when some
source reports needs_samples()) a keydb-only resolve ran with empty
samples and committed a wrong UK as success, muxing undecryptable video
while reporting done. The CLI was unaffected because it always samples.

Override needs_samples() to true on KeydbSource so every consumer samples
encrypted units before resolving and a wrong keydb UK is rejected on all
paths. Regression test asserts the override.
2026-06-23 01:53:36 -07:00
Matthew Jackson 6f164ca355 v1.0.0-rc.3.1: online key-service auth header + cross-OS keydb search paths (paths.rs) 2026-06-22 18:09:48 -07:00
Matthew Jackson 2987792328 v1.0.0-rc.3: bump version 2026-06-22 16:19:11 -07:00
Matthew Jackson bde416604e keysources: expose host certs through KeySource trait
- KeydbSource implements KeySource::host_certs(), delegating to the
  inherent host_certs() — surfaces the | HC | / | HC2 | certs already
  parsed from keydb.cfg by libfreemkv's parser, so the OEM cert route
  collects them across the keysource layer. No new parsing.
- OnlineSource::host_certs() is a no-op stub: returns empty with zero
  network access (no client fetch, no server endpoint). Online host-cert
  serving is deferred. TODO(owner) marker left in place.

Tests: trait host_certs returns the keydb HC row; empty when keydb
missing; online host_certs is an empty no-op without network.
2026-06-22 11:23:46 -07:00
Matthew Jackson 268e1d6bf2 v1.0.0-rc.2: bump version (unified release with libfreemkv 1.0.0-rc.2) 2026-06-22 09:17:07 -07:00
Matthew Jackson cfb90514e9 ci: reword publish note (drop internal-repo reference) 2026-06-22 09:15:17 -07:00
Matthew Jackson c65cbe7f34 ci: add Release workflow (verify + test + GitHub release; crates.io publish driven by release.sh) 2026-06-22 08:54:25 -07:00
Matthew Jackson 0139ba6f1b rc2: SSRF parity, bounded DNS, strict hex parse, over-cap MKB error signaling 2026-06-22 08:47:52 -07:00
Matthew Jackson 3957ac70c1 v1.0.0-rc.1
key sources (keydb/online/mapfile), overflow-safe LBA
2026-06-21 21:06:07 -07:00