Skip to content

installer: harden DKMS Secure Boot signing identity - #89

Merged
Syax89 merged 7 commits into
Syax89:mainfrom
avgbob:upstream/secure-boot-dkms-hardening
Oct 18, 2026
Merged

Syax89 merged 7 commits into
Syax89:mainfrom
avgbob:upstream/secure-boot-dkms-hardening

Conversation

@avgbob

@avgbob avgbob commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Harden the installer/activation Secure Boot path so it validates and enrolls the same signing identity DKMS actually uses, instead of assuming every distribution signs with /var/lib/dkms/mok.key + mok.pub.

This is tooling-only. It does not change the touchscreen driver or either runtime profile.

Why

DKMS signing paths are distro/configuration dependent:

  • Ubuntu-family packaged DKMS commonly uses:
    • /var/lib/shim-signed/mok/MOK.priv
    • /var/lib/shim-signed/mok/MOK.der
  • upstream/Debian defaults commonly use:
    • /var/lib/dkms/mok.key
    • /var/lib/dkms/mok.pub
  • /etc/dkms/framework.conf and framework.conf.d/*.conf can override both.

The previous installer could validate/enroll one certificate and then let DKMS sign the modules with a different key. It also treated certificate existence as sufficient even if the private key was missing or mismatched.

Changes

  • resolve mok_signing_key / mok_certificate from the active DKMS configuration;
  • accept paired SL4A_MOK_KEY + SL4A_MOK_CERT only when they exactly match the signing identity DKMS is configured to use;
  • refuse one-sided or divergent overrides;
  • validate both private key and DER X.509 certificate;
  • prove the key and certificate public keys match;
  • safely convert a PEM certificate to DER when needed;
  • reuse a valid existing pair by default;
  • refuse incomplete/mismatched material non-interactively;
  • allow explicit replacement with --rotate-mok, backing up existing material first;
  • optionally import another existing matching key pair interactively;
  • use the resolved certificate during activate, not a hard-coded DKMS path;
  • verify both installed kernel modules have a signer before continuing when Secure Boot is enabled.

PKCS#11 signing keys are explicitly refused rather than pretending the installer can manage them.

Safety properties

The rotation path is deliberately opt-in because replacing the DKMS signing identity affects all DKMS modules, not just this driver.

Existing MOK material is backed up before deliberate replacement. A partial or mismatched pair is never silently accepted as usable.

Tests

Adds tests/secure_boot_installer_source_test.py to make -C tests test.

The contract test pins:

  • distro defaults;
  • DKMS framework.conf/drop-in resolution;
  • matching key/certificate validation;
  • explicit rotation behavior;
  • no hard-coded MOK path in activation;
  • enrollment against the resolved certificate;
  • installed-module signer verification;
  • bash -n tools/sl4a-touch.sh.

Opened as draft so the maintainer can review the installer UX separately from driver PRs #87 and #88.

Project provenance

This installer hardening is not itself a Windows-protocol change, but it comes from the same hardware qualification campaign that followed the Windows reverse engineering. For context, the functional path being qualified was driven by:

The Secure Boot work exists to make that reverse-engineered driver path reproducible across reboot/DKMS lifecycle testing without confusing signing/enrollment failures for protocol failures.

Review follow-up

The review's pair-A/pair-B concern is fixed using the fail-closed option: the installer first resolves DKMS's actual configured mok_signing_key / mok_certificate; SL4A_MOK_* values are accepted only if they name that same pair. A different installer-only pair is rejected with instructions to configure DKMS itself instead.

The contract test now executes the real resolver in a temporary DKMS-config tree and checks three behavioral cases: configured pair B with no override, override pair A vs DKMS pair B (must fail), and an override that repeats pair B (accepted). --rotate-mok is also in executable --help with the backup behavior and warning that changing the shared DKMS signing identity can affect every DKMS module on the system.

@Syax89

Syax89 commented Oct 16, 2026

Copy link
Copy Markdown
Owner

Thanks for the Secure Boot hardening. I completed two independent review passes and checked the findings with host tests and targeted probes. These are comments for the draft, not a formal approval or change request.

Reviewed head: 469a7cdaf86f845127af03a5d3886cf7539d767c; base: 72b3492ba08fdee481b5dd1fa5781025264583f9.

Medium — custom SL4A MOK overrides are not forwarded to DKMS

tools/sl4a-touch.sh:453–455, called from :760 and :1313: SL4A_MOK_KEY / SL4A_MOK_CERT select the pair validated and enrolled by the installer, but subsequent DKMS build/install calls neither forward that identity nor configure a DKMS framework override. DKMS consumes mok_signing_key / mok_certificate, not the installer's MOK_KEY / MOK_CERT variables.

Consequently, with explicit overrides selecting pair A and framework defaults selecting pair B, the installer can validate/enroll A while DKMS signs with B. The nonempty signer-name check at :1006–1008 does not establish key equality; if only A is enrolled, B-signed modules cannot load under Secure Boot.

Reproduction: with both SL4A override variables exported, the actual installer resolver selected a scratch one.key / one.der, while the extracted upstream DKMS prepare_mok() selected /var/lib/dkms/mok.key / mok.pub. Reference DKMS revision: 7e20e653e915243b56398b0863f6ac4f20900653, dkms.in:1292–1384. OpenSSL writes were blocked in this identity-selection probe; real matching/mismatching key checks were tested separately.

Suggested direction: either make the overrides configure the identity DKMS actually uses, with explicit handling of the global effect, or reject an override that differs from that identity. Add a behavioral test with distinct A/B pairs; checking only that a signer string exists misses this case.

Low — expose the recovery option in help

--rotate-mok is parsed and recommended on failure but absent from executable --help (tools/sl4a-touch.sh:277,292–298). Running the help confirmed the omission. Please list its backup behavior and effect on the shared DKMS signing identity.

Checks and rejected candidates

  • make -C tests test: PASS; Secure Boot source contract, installer recovery contract, tools contract, and 15 hunt-sandbox variants passed. bash -n tools/sl4a-touch.sh and diff whitespace checks passed.
  • Actual OpenSSL probes accepted a matching pair and rejected a mismatched pair and certificate-only material.
  • The negative source guard is effective: inserting the prohibited hard-coded path caused the expected failure. A clean source not matching that guard is not a defect.
  • Refusal after detecting unsigned modules is intentional fail-closed behavior; no regression destroying a working signed installation was demonstrated. Please do not weaken this check on that basis.
  • The proposed same-second backup collision was not established as reachable twice in one installation: relevant callers are mutually exclusive.
  • Root-owned configuration sourcing, incomplete-pair rejection, PEM normalization and explicit PKCS#11 refusal are intentional boundaries, not findings.
  • No platform-specific claim about DKMS encrypted-key support is established by these probes.

Limits

No real DKMS install, enrollment, reboot, module loading, kernel build or Surface hardware test was performed. No remote checks were reported at review time; local test results are not CI results. Source was left unchanged.

avgbob commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

Thanks — agreed on the A/B signing-identity issue. I took the fail-closed option rather than having this installer silently rewrite global DKMS configuration.

Current head: d34fb2534dbbc48fdee8940b6f29d68d3186dfff.

resolve_dkms_mok_paths() now resolves the identity DKMS itself will use first (distro default + framework.conf + drop-ins). A paired SL4A_MOK_KEY / SL4A_MOK_CERT is accepted only when it exactly matches that resolved DKMS pair. A distinct pair A vs DKMS pair B is rejected with an instruction to configure DKMS itself if the operator really wants to change the signing identity.

I added a behavioral resolver test using a temporary DKMS config tree:

  • configured pair B, no override -> resolves B;
  • override pair A while DKMS is configured for B -> fails;
  • override that repeats B -> accepted.

The existing unsigned-module fail-closed check is unchanged.

I also added --rotate-mok to the executable help. The help states that existing material is backed up and that rotation changes the shared DKMS signing identity and can affect every DKMS module on the system.

CI on the updated head is still waiting for fork-workflow approval, so I’m not claiming a new green run yet.

@Syax89

Syax89 commented Oct 16, 2026

Copy link
Copy Markdown
Owner

Thanks — on d34fb2534dbbc48fdee8940b6f29d68d3186dfff I verified the identity correction and executable help. With two real OpenSSL pairs and a temporary framework/drop-in tree, the installer and actual pinned upstream DKMS resolver select B; explicit A is rejected, repeated B is accepted, and a one-sided override is rejected. The previous A/B identity issue is resolved for that tested configuration without changing global DKMS config.

Two test-only issues remain:

Medium: the new warning assertion does not match the real help

tests/secure_boot_installer_source_test.py:28 requires:

affects every DKMS module on the system

but tools/sl4a-touch.sh:296 correctly says:

can affect every DKMS module on the system

The other prompt says affects all DKMS modules, which also does not match. Reproduction:

$ python3 tests/secure_boot_installer_source_test.py
secure boot installer contract missing: system-wide rotation warning
# exit 1

Clean host, SANITIZE=1 and fully C-instrumented aggregates exit 2, before the new behavioral resolver checks run. Please fix the expected token/semantic assertion, not remove the useful warning. The help already documents rotation, backup and shared identity correctly.

Low: the temporary DKMS path rewrite is applied twice

At test lines 111–117, replacing the drop-in glob and then replacing the framework prefix rewrites the already-prefixed temporary path again. The result nests the fixture root twice rather than pointing at its intended etc/dkms/framework.conf.d/*.conf. No drop-in is written by the shipped fixture, so its three cases do not expose this coverage hole. Please use one root substitution and add a real drop-in precedence case.

Independent execution with a single root substitution verifies last-drop-in-wins against actual reference DKMS 7e20e653e915243b56398b0863f6ac4f20900653. In a separate in-memory test copy correcting only the warning token, behavior checks pass and removing the mismatch comparisons is rejected. This does not erase the original gate failure. Matching/mismatching/garbage/missing key/cert controls used actual OpenSSL; no credential material is published.

Both modules and explicit replay target compile against existing Debian 6.12.111 headers (BTF disabled); later tools/descriptor/hunt checks also passed when run separately. bash -n, help and diff checks pass. No actual DKMS installation, enrollment, reboot or signed-module loading was performed. Distro-package defaults outside the tested explicit configuration remain a portability qualification boundary. CI is action_required, not green. No source changes made.

avgbob commented Oct 16, 2026

Copy link
Copy Markdown
Contributor Author

@Syax89 The two host-test follow-ups are corrected at 879a13d. The help contract now matches the actual "can affect every DKMS module" wording. The scratch resolver now substitutes the common /etc/dkms/framework.conf prefix exactly once, and a real 90-identity.conf drop-in overrides the framework pair to exercise lexical precedence. Existing A-vs-B mismatch, matching-pair and fail-closed checks remain.

Fork CI run 38925987371 is green for normal and sanitizer host gates and both kernel builds. No real MOK rotation, DKMS reinstall or reboot was performed; PR stays draft for exact installer/Secure Boot hardware acceptance and distro portability.

@Syax89

Syax89 commented Oct 16, 2026

Copy link
Copy Markdown
Owner

Thanks again for the fixes. Here is the focused follow-up verification.

Reviewed exact head 879a13dfcfdd52cbe5332e284da43d794b5f827d. The warning/help contract correction and real drop-in rewrite control pass unchanged; the original complete framework/drop-in identity and divergent explicit-override corrections remain valid.

The distro-default qualification now goes beyond latest-upstream/synthetic evidence. I downloaded and extracted, without installing:

  • Ubuntu Noble dkms 3.0.11-1ubuntu13, including its actual /usr/sbin/dkms, packaged framework.conf (MOK settings commented out) and empty framework.conf.d/;
  • Zorin's Noble base-files 13ubuntu10.4+zorin2, whose actual os-release identifies Zorin OS18.1, ID=zorin, ID_LIKE="ubuntu debian";
  • the matching Ubuntu DKMS source archives and repository package indices. The downloaded DKMS binary and Zorin base-files SHA256 values match their HTTPS package-index records; this is not a claim of a separately verified APT signature chain or a live installed-machine inventory.

Executing the exact installer resolver/validator and actual packaged DKMS distro_version/read_framework_conf/prepare_signing functions against redirected scratch paths, actual Zorin os-release, shipped default config and two existing valid distinct generated pairs gives:

Case Installer Packaged DKMS
Ubuntu ID control, no explicit MOK config shim-signed pair same shim-signed pair
Actual packaged Zorin18.1 identity, no explicit MOK config /var/lib/dkms/mok.key + mok.pub /var/lib/shim-signed/mok/MOK.priv + MOK.der
Zorin, complete base pair A overridden by drop-in pair B pair B pair B
Divergent installer-only override A vs configured B rejected B remains configured
Explicit override repeating configured B B B

The packaged DKMS classifier returns the scalar string ubuntu debian, which matches its ubuntu* signing branch. The installer keys only on an ID allow-list which excludes zorin; its package-manager-family normalization does not repair this choice. No key generation/enrollment/sign command was allowed in the selection probes; scratch pairs were removed afterwards.

This establishes a remaining packaged-default identity-selection bug for the tested Noble/Zorin combination, not just an upstream portability hypothesis. With both distinct pairs present, the installer can validate a different identity from the one DKMS selects for signing. A load/enrollment failure is conditional on the actual machine's keys and enrollment state; none was induced or claimed. Complete explicit framework/drop-in overrides remain a passing control.

Please either make the default resolver match the supported packaged DKMS behavior or qualify/refuse this unresolved default case before claiming the same identity universally. Also, manual recovery docs should use the resolved certificate rather than universally importing /var/lib/dkms/mok.pub. Do not rotate a working shared MOK to work around this: it affects other DKMS modules.

Scope limits: downloaded Noble release package and published Zorin base-files; no installed Zorin inventory, package installation, real signed module build, MOK enrollment, boot or module load. Zorin's examined Noble repositories expose no replacement dkms entry, and its official live-session list has no preinstalled dkms; this supports repository compatibility, not a claim that every Zorin machine uses this version. Jammy DKMS2.8.7 has a different signing interface and was only inspected, not qualified by the Noble harness. Custom signers, module-specific overrides, other versions/distros and full Secure Boot lifecycle remain separate acceptance work.

@Syax89
Syax89 marked this pull request as ready for review October 18, 2026 10:40
@Syax89
Syax89 merged commit 5a3d730 into Syax89:main Oct 18, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants