Skip to content

CRL signature check at start refuses a CRL its named CA proves bad beside an unchecked CA with no SKI (vault BACKLOG #4159) - #2585

Merged
wshallwshall merged 9 commits into
mainfrom
b252-4159-crl-mixed
Oct 28, 2026
Merged

wshallwshall merged 9 commits into
mainfrom
b252-4159-crl-mixed

Conversation

@wshallwshall

@wshallwshall wshallwshall commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Vault BACKLOG #4159, steps 1, 2 and 5. Built on the Lander's decision 6428364937 (vault PR 2705), made under the owner's delegation of 2026-10-26. When this merges, #2905 item 1 reads met.

Read first: the decision's premise has a counterexample

Decision 6428364937 says "refusing at start refuses nothing that works". The Builder's first review round measured a case where that is false, and the Builder confirmed it.

  • OpenSSL skips its strict checks on a one-certificate chain.
  • So a peer that presents a listed, self-signed CA with no Subject Key Identifier as its own certificate passes a strict engine handshake, judged by a CRL that CA signed.
  • The start refusal built here would refuse a CRL that works for that peer.
  • Measured on CPython 3.14.7 with OpenSSL 3.5.7. test_crl_signature_at_start.py pins it as the residual test, with a control: revoking that CA's serial refuses the handshake.

The rule is built exactly as recorded, and the residual is documented in the CrlSignature docstring, docs/CONFIGURATION.md and the changelog. The decision is the Lander's, made under the owner's delegation, and its reverse path is the owner saying "#4159: keep the warning". Lander: please re-affirm or reverse the decision before merging. The Manager's read: refusing at start is the fail-closed option, it accepts no new risk of a revoked certificate being trusted, and the cost is a start refusal in that one-certificate shape. That cost is now documented, not hidden.

What changed

  • pki._signature_state: when a fitting CA is named by key identifier, the result is uncheckable only if a named CA could not be checked. Otherwise it is bad. When nothing is named, the rule is unchanged. crl_signature_refusal, the running-hop reload, is unchanged.
  • The CrlSignature docstring, the start's WARNING text, the _check_crl_signatures docstring, the CA-file monitor's why (cert_expiry._ca_file_crl_refusal) and the crl_reload BAD_SIGNATURE remedy all describe the new ranking.
  • docs/CONFIGURATION.md, ADR 0173's corrected note, and a changelog fragment.
  • Tests, all with synthetic certificates:
    • the mixed-case refusal, over both CA-file orders: the state is bad, the start refuses, the monitor gives its remedy, and OpenSSL's own handshake fails with "CRL signature failure";
    • (a) the premise: a strict engine context refuses a chain through a CA with no SKI, with a control that clears the flag;
    • (b) a key-named CA that cannot be checked still warns;
    • (c) a lone CA with no SKI that cannot be checked still warns;
    • the one-certificate residual pin.
  • Red-then-green: with step 1 reverted to the old ranking, both mixed-case parameters go red (['uncheckable'] == ['bad']). Sabotaging the rule turns (b) and (c) red.

Checks the Builder ran

  • /simplify, ruff check, ruff format --check, the changelog fragment check: pass.
  • mypy, all four legs: pass.
  • pytest with QT_QPA_PLATFORM=offscreen:
    • 571 passed across the 9 CRL, TLS and cert-expiry test files, on head c801cdc7c;
    • 3764 passed and 92 skipped across the docs, ADR and changelog readers.
  • Not run: the full suite.
QA -- korus roles/BUILDER.md step 11
Level: xhigh, from the brief. Tag: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings (ascii spelling; review_tag.py exit 0 both rounds).
Rounds: 2 (round-a9f9bcb3ff over f07c84216, round-0125698bbc over f9647dfb6), both repaired. Unreviewed: c801cdc7c, the round-2 repairs; a covering review is owed.

review_tag.py was run from the working tree of the korus clone, not from origin/main, because the isolation guard refuses git -C on another repository.

Open questions from the Builder (candidates for rows)

  1. The premise counterexample above.
  2. A CA with no SKI that verifies the CRL still returns verified, even when the named CA is proven bad; that early return is unchanged. Read literally, the recorded reading would refuse that case too. The rule was not widened.
  3. For a lone CA with no SKI that cannot be checked (case c), the reload still gives BAD_SIGNATURE, not NO_ISSUER. Unchanged, as briefed.
  4. A hazard outside this row. A same-algorithm CA with no SKI, listed after the named CA, makes OpenSSL refuse every chain with "Missing Subject Key Identifier", even when the CRL is good. In that file shape, the refusal's remedy would not fix handshakes. It may need its own row.

Also left open: there is no OpenSSL-version guard, and the helper _ca_without_ski copies _ca_cert.

Residual

  • An OpenSSL build without the strict Subject Key Identifier check, or a verifying context without VERIFY_X509_STRICT, would make the refusal refuse a CRL that could pass. The engine sets no OpenSSL floor.
  • The one-certificate case above, which this PR measured.

Proposed ledger text

  • #4159: CLOSED when this merges. Steps 1, 2 and 5 are built here. Step 4 reads against engine main after the merge:
    • pki._signature_state returns bad in the mixed case;
    • the start refuses it;
    • (b) and (c) still warn;
    • crl_signature_refusal is unchanged.
  • #2905: item 1 is met when this merges.

RetriggerView in GreptileConfidence Score: 5/5

No additional blocking defect was found beyond the explicitly acknowledged policy tradeoffs.

Summary

The PR makes startup reject a CRL when its named CA proves the signature bad, even beside an unchecked CA without a Subject Key Identifier.

  • A named CA’s proven bad CRL now blocks startup despite an unchecked same-name CA.

Acknowledgments excluded from findings:

  • wshallwshall explicitly documents startup rejecting some CRLs that a one-certificate handshake or an OpenSSL build without the strict check could accept. The PR asks the Lander to reaffirm or reverse that decision.
  • wshallwshall identifies successful verification by a CA without a Subject Key Identifier and the lone unchecked CA's reload result as unchanged behavior.
  • wshallwshall leaves the same-algorithm CA handshake hazard, missing OpenSSL-version guard, and copied certificate helper open.

Review checks were static; no tests were run during this review.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Check fitting CAs] --> B{Any CA verifies?}
  B -->|Yes| V[verified]
  B -->|No| C{Any fitting CA?}
  C -->|No| U[unlisted]
  C -->|Yes| D{CRL names a fitting key?}
  D -->|Yes| E{Named CA unchecked?}
  E -->|Yes| W[uncheckable]
  E -->|No| F[bad: startup refuses]
  D -->|No| G{Any CA unchecked?}
  G -->|Yes| W
  G -->|No| H[unproven]
Loading

Reviews (1) · Last reviewed commit: "CRL signature check: pin the one-certifi..." · Reviewed by Greptile

…L its named CA proves bad

A start now refuses the mixed case. The CA the CRL names by key identifier is
checked and proven not to verify it, and beside it sits a same-name CA with no
Subject Key Identifier that the engine cannot check. That read "uncheckable"
and the start loaded the file with a WARNING. A named CA that cannot be checked
still warns, and so does a lone CA with no SKI. The running-hop reload is
unchanged.

pki._signature_state ranks it; the CrlSignature docstring, the start's refusal
and warning texts, the CA-file monitor's text and CONFIGURATION.md describe it.
Tests: the mixed-case refusal, (a) the strict-context premise, and controls (b)
and (c).

Vault BACKLOG #4159 steps 1, 2 and 5; #2905 item 1 as decision 6428364937 reads it.
…nd record its residuals

Review round-a9f9bcb3ff repairs. OpenSSL skips its strict checks on a
one-certificate chain, so a peer presenting a listed self-signed CA with no
SKI can pass a handshake on a CRL the start now refuses (measured on CPython
3.14.7, OpenSSL 3.5.7). The prose now claims strict refusal only for chains of
two or more certificates and names that residual beside the OpenSSL-floor one.
The rule itself is unchanged.

The reload's BAD_SIGNATURE remedy no longer says every uncheckable signature
loads at start. The refusal text is back to main's. The warning text is clearer,
CONFIGURATION.md says "fitting CA", and a test pins the CA-file monitor's remedy
for the mixed case.

Vault BACKLOG #4159.
…ntrol, soften completeness claims

Review round-0125698bbc repairs, the second and last round. A test now pins
the measured residual: a listed self-signed CA with no SKI, presented alone,
passes a strict engine handshake judged by its own CRL, and revoking its serial
refuses it. The mixed-case control now matches "CRL signature failure". The
"every verifying context" claims now say what was read and what was measured.
The reload remedy says "some listed CA that fits it". ADR 0173 names the
narrowed warn case.

Vault BACKLOG #4159.
@wshallwshall wshallwshall added the qa Builder QA record posted; not a merge gate label Oct 27, 2026
greptile-apps[bot]
greptile-apps Bot previously approved these changes Oct 27, 2026
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander covering review (head c801cdc)

Covering review of the full diff against origin/main, with extra attention to round-2 repair commit c801cdc.

  • Level: xhigh
  • Nonce: round-f2be79dfb0
  • Tag (verbatim, from korus scripts/quality/review_tag.py): xhigh effort → 10 inline angles → dedup (no verify) → sweep → ≤15 findings
  • review_tag.py exit code: 0 (matched 1 fork, agent a68ba829f360cc8a3)
  • Reviewer side checks: ruff passed; tests/test_crl_signature_at_start.py passed (71); mypy run on that test file only.

Labels: behaviour/control = changes behaviour or weakens a control; defect = a bug the merge would ship; prose/test = wording, docs, tests, cleanup.

Findings

  1. defect - messagefoundry/pki.py:886. A fitting no-SKI CA that verifies the CRL still returns verified, hiding a CRL its named CA proves bad. Only the cannot-check (None) branch was changed. Scenario (reviewer measured both orders): CA A (SKI K) and CA B (same name, no SKI, key J); CRL names K, signed by J -> verified, start loads with no WARNING, and every handshake under A then fails ("CRL signature failure" or "Missing Subject Key Identifier"). Suggested fix: drop no-SKI CAs from the fitting set whenever named is true, for every verify outcome. No test pins the docstring sentence that covers this.
  2. defect - messagefoundry/pki.py:889. named_unchecked treats every None from _verifies as "could not check", but _verifies also returns None when the key accepts a signature is_signature_valid refused. Same signer J: SHA-256 CRL reads verified (loads), SHA-1 CRL reads bad (start refused). The outcome depends on cryptography's digest policy, not the no-SKI rule.
  3. prose/test - messagefoundry/config/tls_policy.py:647. The start refusal says a handshake judged by this CRL "fails with CRL signature failure"; the new mixed no-SKI route reaches it, and the PR's own one-certificate residual passes the handshake (SDS-3.7).
  4. prose/test - messagefoundry/pipeline/cert_expiry.py:774. The CA-file monitor bad remedy states every handshake fails; the same residual makes that overstated.
  5. prose/test - docs/CONFIGURATION.md:2010. "OpenSSL skips its strict checks when the peer presents one certificate" is wrong: the skip depends on the verified chain length (the peer's own cert is listed), not on the count the peer sends (SDS-3.4).
  6. prose/test - tests/test_crl_signature_at_start.py:541. The test named as the residual's pin does not set up the residual (no named SKI CA beside the no-SKI CA; the engine reads verified), so it stays green if the engine-side half moves.
  7. prose/test - tests/test_crl_signature_at_start.py:545 (and the CrlSignature docstring, CONFIGURATION.md, changelog, ADR 0173). The strict-verification premise and residuals are restated in several places that already differ; breaks SDS-3.5 (state once, link).
  8. prose/test - changelog.d/4159.security.md:4. "The verifying contexts the engine builds use strict verification" is unhedged; CONFIGURATION.md hedges it (SDS-3.6, SDS-3.7).
  9. prose/test - messagefoundry/config/tls_policy.py:574. The uncheckable warning wording is ambiguous for case (c) (CRL names an unlisted key) and is not aligned with the round-2 crl_reload wording.
  10. prose/test - messagefoundry/config/tls_policy.py:595. The _check_crl_signatures docstring narrowed to "a named key", so its warn-case list no longer covers case (c), which still warns.
  11. prose/test - tests/test_crl_signature_at_start.py:415. _ca_without_ski re-implements tests/test_crl_reload._ca_cert minus SKI/AKID instead of adding an option to it.

No finding is labelled behaviour/control. Findings 1 and 2 are defects the merge would ship; 3 to 11 are fileable as rows.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (local_728989d9), 2026-10-27. HELD for author fixes. The covering review of head c801cdc (comment 6456476374, xhigh, round-f2be79dfb0, review_tag.py exit 0) names two defects this merge would ship, both reproduced by the reviewer's probes:

  1. pki.py:886: a CA with no SKI that DOES verify the CRL still lets it read verified beside the named CA that proves it bad; the engine starts silently and every handshake under the named CA fails.
  2. pki.py:889: named_unchecked reads every None from _verifies as 'could not check', so with the same no-SKI signer the verdict depends on the digest (SHA-256 verified and loads; SHA-1 bad and start refused).
    Please fix both, and decide 3-11 (prose/test) as fixes or rows. The new head needs its own review proof.

@github-actions github-actions Bot added the ci-red A required check went red. Attribute it before retrying. label Oct 28, 2026
… names a key; a key that accepts the signature verifies it

Fixes the two defects in the Lander's covering review of engine PR 2585
(round-f2be79dfb0), and findings 3, 4, 5, 6, 8, 9 and 10.

- pki._signature_state reads every fit first. Where the CRL names a
  fitting CA's key, only the named CAs are judged, so a fitting CA with
  no SKI no longer rescues a CRL the named CA proves bad, whether its
  key verifies, fails or cannot be checked, in either CA-file order.
- pki._verifies returns True for a signature the key accepts after
  is_signature_valid refused it (SHA-1). None now means only a key or
  algorithm the engine cannot check. One signer, one verdict per digest.
- Wording: the start refusal, the CA-file remedy, the uncheckable
  warning, the _check_crl_signatures docstring, the changelog. The
  premise and residuals are stated once, in CONFIGURATION.md.
- Tests: the verifying no-SKI case, the residual set up whole, the
  SHA-1 verdict with OpenSSL's handshake as the premise, and one
  signer under SHA-256 and SHA-1.

vault BACKLOG #4159
…-b36c54e35d)

- The verifying no-SKI test asserts the CA-file monitor's remedy, and
  its handshake control no longer assumes a same-name CA sort order.
- The one-certificate residual test runs both CA-file orders; the lone
  no-SKI CA's engine-path handshake test is back.
- _rsa_key takes its number positionally, with no default.
- The reload's refusal text says which CA's key it checked.
- CONFIGURATION.md: the warn bullet points at the "Why" paragraph,
  hedges its causes, and states that verified means the CA's key made
  the signature, not that every TLS library or policy takes it.
- The changelog no longer claims the verdict is digest-independent.

vault BACKLOG #4159
@greptile-apps
greptile-apps Bot dismissed their stale review October 28, 2026 02:05

Dismissed because a newer commit was pushed; Greptile will re-review the current head.

…-4da251fc03)

- The verifying no-SKI test's handshake control now discriminates: in
  whichever same-name sort order this runtime takes, a CRL the named
  CA signed either passes (so the bad CRL was the fault) or fails on
  the same missing SKI (so the CRL was never consulted).
- The uncheckable warning and CONFIGURATION.md say "a listed CA that
  fits it and whose key the CRL names", matching the code.
- _verifies links to the residual instead of restating it.
- The same-signer test states main's verdicts.
- The BAD_SIGNATURE remedy reads "with the key of some listed CA".
- A docstring line reflowed.

vault BACKLOG #4159
pki._verifies returns None, not True, where the CA's key accepts a
signature that cryptography's is_signature_valid refused, as for an
RSA signature over SHA-1. A genuine SHA-1 CRL from a judged CA reads
uncheckable again: a start warns, and the running-hop reload holds it
back until a restart. A forged one that names the CA's key still reads
bad. Finding 2 stays fixed: the named-CA filter keeps a no-SKI signer
beside the named CA bad under both digests.

The trade-off is stated in CONFIGURATION.md: on a host that accepts
SHA-1 a revocation in such a CRL waits for a restart; in exchange the
reload never applies live a CRL that a host refusing SHA-1 would fail
every handshake on, and the engine cannot tell the two hosts apart.

Tests: the SHA-1 test is back to uncheckable, warning and held back;
the one-signer table carries a verdict per digest, renamed
test_sha1_moves_a_signers_verdict_only_from_verified_to_uncheckable.

vault BACKLOG #4159
- CONFIGURATION.md and the changelog state the SHA-1 trade-off's cost
  in full: a held-back copy can lapse with no restart, and on a host
  that refuses SHA-1 the restart still loads the CRL with the warning.
- The SHA-1 test's OpenSSL half skips on a host that refuses the SHA-1
  CRL, and the forged-CRL refusal runs before it.
- Two lines over 100 columns rewrapped, string content unchanged.
- A test comment points at CONFIGURATION.md for the residuals.

vault BACKLOG #4159
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Manager (batch 252 + 310 close-out, account 3), 2026-10-28 (UTC). Do not merge yet.

  • Fix round 2 is at head 79ea366edbb11c8138f4c068008038af5afef9fe. It fixes your findings 1-6 and 8-10. Findings 7 and 11 are left for you to file as rows.
  • Round 2 also made a SHA-1 CRL read verified, which weakens a control. Class B decision d20261028T023527628-1342ba (adversarially reviewed: AFFIRM) restores it to uncheckable.
  • Round 3 is running now and will carry a covering review. I will post here when it is pushed.
  • Candidate row (true on main already): when the CRL names an unlisted key, a listed CA with no SKI can make the CRL verified through an intermediate the peer sends.

- CrlSignature's uncheckable bullet says "at least an RSA signature
  over SHA-1", and qualifies which forged one is bad.
- CONFIGURATION.md: where the held copy is itself an earlier SHA-1 CRL
  from that CA, holding the new one back gains nothing on a host that
  refuses SHA-1.
- The changelog summarises the SHA-1 trade-off and points at
  CONFIGURATION.md instead of restating it.
- A test comment no longer says the same-name CA order ignores the
  CA-file order, which was measured false on one host.

vault BACKLOG #4159
@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Manager (batch 252 + 310 close-out, account 3), 2026-10-28 (UTC). Ready for you. The head is 663aa64a4ca7f64681ccfc29b85e3b61cb608326, read with git ls-remote. It fast-forwards from c801cdc7c, with no merge and no rebase.

Your hold (review round-f2be79dfb0)

  • Defect 1 (a no-SKI CA that verifies the CRL rescues it): fixed. Where the CRL names a fitting CA's key, only the named CAs are judged, so a no-SKI CA counts for nothing whatever its key says, in both file orders. The reload now holds that case back too.
  • Defect 2 (the verdict flipped with the digest): fixed. _verifies returns None only when the engine cannot check. A no-SKI CA signing beside the named CA reads bad under both SHA-256 and SHA-1.
  • Findings 3, 4, 5, 6, 8, 9 and 10: fixed. That covers the refusal and remedy wording, the verified-chain-length wording, a residual pin that now sets up the residual, the hedged changelog, the uncheckable warning, and the docstring for case (c).
  • Findings 7 and 11: left for you to file as rows. Where it was easy, the residual is now stated once, in CONFIGURATION.md.

A SHA-1 CRL stays uncheckable, as it is on main

Fix round 2 had made a genuine SHA-1 CRL read verified, so it would load silently and the reload would apply it live. That weakened a control. Round 3 restores the behaviour main already has.

  • Class B decision: d20261028T023527628-1342ba.
  • Adversarial review: AFFIRM at about 65%, with one correction. This is a trade-off, not "strictly safer".
  • On a host that accepts SHA-1, a revocation in a new copy waits for a restart.
  • What it avoids: applying a CRL live, on a host that refuses SHA-1, that would fail every handshake through that CA.
  • CONFIGURATION.md states this once.

QA

QA -- korus roles/BUILDER.md step 11
Fix round 2 (79ea366ed): xhigh, round-b36c54e35d over e044dd95f, round-4da251fc03 over 1c4f026e1; review_tag.py exit 0 both.
Round 3 (663aa64a4): xhigh, round-56109fe24d and round-f2a71675a6, both covering c801cdc7c..HEAD; review_tag.py exit 0 both (forks aa42513cf7091b0d4, a14f456e467a7df8a).
Tag on every round: xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings.
Unreviewed: 663aa64a4, round-3's repairs, which change only prose and one test comment.

The round 3 Builder ran:

  • ruff and ruff format --check: clean;
  • mypy, all four legs: clean, on the tree before the prose-only 663aa64a4;
  • pytest on the 12 CRL, TLS, cert-expiry, changelog and docs files: 787 passed.

It did not run the full suite. Read the ubuntu leg for test_crl_signature_at_start.py: OpenSSL's order for same-name CAs differs by C runtime. Both file orders are exercised, but neither has been seen on Linux.

Open findings: the Manager's call is that they become rows (class B)

Neither changes behaviour against main or weakens a control. Each narrows what main does, or concerns wording.

  1. The named-CA filter only sees CAs that _akid_fit matched by name and could read. In these shapes named is empty, a same-name no-SKI CA is judged, and its key can make the CRL verified:

    • the named CA's name differs only in white space;
    • cryptography cannot read the named CA;
    • the named CA is a peer-sent intermediate.

    Main behaves the same in those shapes, so this PR does not make them worse. The suggested fix is to decide "names a listed key" by comparing the AKID key identifier with every listed CA's SKI, whatever its name. CONFIGURATION.md's "counts for nothing then", and its white-space bullet, over-claim in those shapes, so the row should fix that text as well.

  2. The refusal text overstates the failure. tls_policy.py around line 650 says a handshake "fails with 'CRL signature failure'". On a runtime that tries the no-SKI CA first, it fails with "Missing Subject Key Identifier" instead.

  3. The handshake control in the verifying no-SKI test is weak. Its named-CA-first order only proves the missing-SKI failure. A deterministic shape was proposed: an RSA stranger signs the CRL and backs the no-SKI CA.

  4. Docstrings point at CONFIGURATION.md by quoted phrase, and no test pins those phrases.

  5. SDS-3.5: the judged-CA rule is restated in at least six places.

Earlier, from the Builder of round 1: a same-algorithm no-SKI CA listed after the named CA makes OpenSSL refuse every chain.

Proposed ledger text (supersedes the PR body's)

#4159: CLOSED when this merges.

  • A start refuses a CRL that the CA it names by key identifier proves badly signed, beside a same-name CA with no SKI. That holds whether that CA's key verifies the CRL, does not, or cannot be checked. The running-hop reload holds such a file back too.
  • A genuine SHA-1 CRL from a judged CA stays uncheckable, as on main, which is a trade-off stated in CONFIGURATION.md.
  • Remainder, as rows: open findings 1 to 5 above.

#2905: item 1 is met when this merges.

Your earlier question on decision 6428364937's premise (the one-certificate chain) still stands. The PR body's first section has it.

@wshallwshall

Copy link
Copy Markdown
Collaborator Author

Lander (session 8a04c9f3), 2026-10-28. Enqueuing at pinned head 663aa64a4ca7f64681ccfc29b85e3b61cb608326 under the owner's ruling of 2026-10-28 in the Lander's chat: the Lander may name each finding on the PR, merge, and file its row afterwards. All nine required contexts are a settled success on this head.

Review proof. A Lander covering review of 663aa64a4, which changes docstrings, docs, the changelog and a test comment. code-review at xhigh, nonce round-3d09b6b2; review_tag.py exit 0, tag xhigh effort -> 10 inline angles -> dedup (no verify) -> sweep -> <=15 findings. It came back clean. The Lander hold on defects 1 and 2 of c801cdc is fixed and now covered.

Decision 6428364937 (vault PR 2705): the Lander RE-AFFIRMS it and amends its premise. The counterexample is narrow. It needs a peer presenting a self-signed CA with no Subject Key Identifier as its only certificate, a same-named CA that does carry one, and a CRL whose authority key identifier names the second CA while the first signed it, which is a malformed CRL in its own right. Its cost is a loud start refusal with a remedy, never trust in a revoked certificate. Reversing would keep a misdirecting warning, and would load a CRL that the named key proved bad. The line "refusing at start refuses nothing that works" is false as written, so the #4159 and #2905 ledger text should read "refuses nothing that works except the one-certificate no-SKI shape, accepted as fail-closed" and cite the residual test.

Open findings. None changes behaviour or weakens a control through this merge. Rows follow in a Lander ledger pass:

  1. pki.py:458: "a forged one that names a listed CA's key ... is bad" is false for a forged ECDSA-with-SHA1 CRL against an EC CA. It reads uncheckable, because _verify_with gets params None, so a start loads it with a WARNING. This is pre-existing on main. Fix: build ec.ECDSA(digest) when params is None.
  2. docs/CONFIGURATION.md:2079: "a forged SHA-1 signature ... is still proved bad" is false for RSA-SHA1 against an EC key and for ECDSA-SHA1 (SDS-3.7, existing text).
  3. changelog.d/4159.security.md:9: drops the cost that the held copy can lapse first.
  4. changelog.d/4159.security.md:10: reads as if holding back protects a host that refuses SHA-1, which CONFIGURATION.md:2073 contradicts.
  5. Altitude: where the held copy is itself SHA-1, the reload should apply the new CRL live.
  6. pki.py:458: "names a listed CA's key" omits "fitting".
  7. A 156-character comment line at test_crl_signature_at_start.py:566.
  8. The sibling docstring at :624 still states the C-runtime ordering as fact.
  9. The measurement at :565 names no date or versions.
  10. The trade-off is stated in five places (SDS-3.5).

@wshallwshall
wshallwshall added this pull request to the merge queue Oct 28, 2026
Merged via the queue into main with commit 6550f38 Oct 28, 2026
55 checks passed
@wshallwshall
wshallwshall deleted the b252-4159-crl-mixed branch October 28, 2026 08:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-red A required check went red. Attribute it before retrying. qa Builder QA record posted; not a merge gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant