Skip to content

certman: require keyCertSign on self-issued peer intermediates - #1294

Open
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/certman
Open

yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/certman

Conversation

@yosuke-wolfssl

@yosuke-wolfssl yosuke-wolfssl commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Problem

CertManIntermediateIsCA() skipped the keyCertSign check for any peer intermediate with DecodedCert.selfSigned set. In released wolfSSL that flag is only an issuer-name == subject-name compare, so a self-issued intermediate (for example a CA key rollover cert signed by its parent's key) whose KeyUsage lacks keyCertSign was promoted into the trust store and could then sign leaves. This check is the only keyCertSign gate for peer intermediates, since they are loaded as WOLFSSL_USER_CA, which wolfSSL does not check. Exploiting it needs a trusted CA to have issued such a cert, so this closes a policy gap rather than an open hole.

Fix (src/certman.c)

  • CertManIntermediateIsCA() no longer exempts selfSigned: every promoted intermediate whose KeyUsage extension is present must assert keyCertSign. The field is no longer read, so no wolfSSL version guard is needed.
  • Trade-off: a trusted root whose KeyUsage lacks keyCertSign (non-conformant per RFC 5280) is now rejected if the peer includes it in the chain; a comment at the check records this. Once wolfSSL PR #11334 ships (selfSigned then means the cert's own key verifies it), the exemption can return behind a version check.

Tests (tests/unit.c)

Case Expected
Self-issued intermediate, keyCertSign chain verifies through it
Self-issued intermediate, digitalSignature only rejected
Chain ending in the trusted root root promoted, chain verifies
  • Forged certs carry SKID and AKID, so the leaf finds its signer by key rather than by the issuer name the self-issued intermediate shares with the root.
  • A promoted case must now verify the whole chain (WS_SUCCESS, or WS_CERT_PROFILE_E from the FPKI profile check), not just avoid WS_CERT_NO_SIGNER_E.
  • The self-issued cases first confirm that the forged cert's issuer and subject name hashes match.

Verification

  • make check 14/14 against wolfSSL v5.9.4 (--enable-all); gcc-13 preflight clean across 6 configs; unit.test passes against an RSA-off wolfSSL.
  • Negative control: with the exemption restored, the self-issued digitalSignature case is promoted and the chain verifies against v5.9.4 (test fails); against the wolfSSL PR #11334 head the tests pass, matching that PR's semantics.

@yosuke-wolfssl yosuke-wolfssl self-assigned this Oct 2, 2026
Copilot AI balanced review requested due to automatic review settings October 2, 2026 07:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The focused security fix is consistent with certificate validation requirements and has targeted regression coverage.

Review effort: Balanced
Findings: None

What changed in this PR

Strengthens certificate-chain validation by enforcing keyCertSign for self-issued peer intermediates.

Changes:

  • Removes the unsafe selfSigned exemption.
  • Adds self-issued certificate generation and regression coverage.
  • Covers peer chains that include the trusted root.
File Description
src/​certman.c Enforces keyCertSign for all peer intermediates with KeyUsage.
tests/​unit.c Tests valid and invalid self-issued intermediates and appended roots.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #1294

Scan targets checked: wolfssh-src, wolfssh-bugs
Coverage: 2 of 2 in-scope changed file(s) opened by the reviewer

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Review tier: Lite

- CertManIntermediateIsCA() demotes a CA intermediate whose KeyUsage
  extension lacks keyCertSign whether or not it is self-issued.
- certmanForgeCert() takes the subject name from issuerCert when cn is
  NULL, and with WOLFSSL_CERT_EXT sets the subject and authority key
  ids.
- certmanIsSelfIssued() reports whether a cert's issuer and subject
  name hashes match; tests/unit.c includes asn.h for it.
- certmanCheckIntermediate() gains selfIssued, which gives the
  intermediate the root's subject name and fails with -935 when the
  forged cert is not self-issued, and appendRoot, which also sends the
  trusted root at the end of the chain. A promoted case passes only on
  WS_SUCCESS or WS_CERT_PROFILE_E.
- test_CertMan_PromoteValidCaIntermediate() covers a self-issued
  intermediate with and without keyCertSign, and a chain that ends in
  the trusted root.
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.

4 participants