Skip to content

Skip same-name extra roots in alternate chain mode - #12077

Open
Frauschi wants to merge 1 commit into
wolfSSL:masterfrom
Frauschi:alt_chain_same_dn_root
Open

Frauschi wants to merge 1 commit into
wolfSSL:masterfrom
Frauschi:alt_chain_same_dn_root

Conversation

@Frauschi

Copy link
Copy Markdown
Member

Description

With WOLFSSL_ALT_CERT_CHAINS, a peer chain ending in an extra self-signed root that shares a trusted CA's name, but has another key and no AKID, failed with ASN_SIG_CONFIRM_E or ASN_SIG_OID_E. NSS sometimes sends such chains, and RFC 8446 section 4.4.2 asks implementations to tolerate extraneous certificates.

Changes to handle this:

  • Skip a chain CA that fails its own signature check when it is self-issued, has no AKID, and the CA found for it has a different public key (SelfIssuedCaKeyDiffers()).
  • Only errors from parsing the CA count; its OCSP and CRL errors are not skipped.
  • genintcerts.sh generates the new test chains from existing keys.

Security

A skipped certificate is never trusted. It is not added to the certificate manager, and the peer certificate must still verify to a CA the client already trusts, so a forged root gains nothing. A chain CA with an AKID, one that is not self-issued, or one carrying the trusted CA's own key still fails on a bad signature, as before.

Testing

  • test_wolfSSL_alt_chain_same_dn_root: same-name roots with an ECC and an RSA key pass with alternate chains and fail with ASN_SIG_CONFIRM_E / ASN_SIG_OID_E without them.
  • test_wolfSSL_alt_chain_bad_sig: a root with the trusted CA's key, a root with an AKID naming that CA, a non-self-issued CA and server-cert-rsa-badsig.pem fail with ASN_SIG_CONFIRM_E in both modes.

@Frauschi Frauschi self-assigned this Nov 10, 2026
Copilot AI balanced review requested due to automatic review settings November 10, 2026 10:20
@github-actions

github-actions Bot commented Nov 10, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report · Explore what changed →

gcc-arm-cortex-m0plus

  • FLASH: .text +48 B (+0.1%, 71,119 B / 262,144 B, total: 27% used)

gcc-arm-cortex-m3

  • FLASH: .text +28 B (+0.0%, 132,049 B / 262,144 B, total: 50% used)

gcc-arm-cortex-m4-pq

  • FLASH: .text +64 B (+0.0%, 313,168 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m7

  • FLASH: .text +64 B (+0.0%, 209,356 B / 262,144 B, total: 80% used)

zephyr-frdm_rw612

  • FLASH: datas +16 B, log_const_area -8 B, rodata -8 B, text +3,928 B (+1.4%, 286,392 B / 67,108,864 B, total: 0% used)
  • RAM: bss +49 B, datas +16 B (+0.1%, 58,423 B / 983,040 B, total: 6% used)

No memory changes detected for:


Catch memory regressions in CI with MemBrowse. Free for open source.

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.

🟡 Changes recommended

Certificate checks can incorrectly skip bad signatures for issuer/serial-only AKIDs or differently encoded identical ECC keys, and the new PEM-based tests fail in supported builds without PEM-to-DER support.

3 open issues
What changed in this PR

This PR updates wolfSSL’s alternate certificate-chain handling to tolerate extra same-name roots with different keys, while still requiring the peer certificate to verify through a trusted CA.

Changes:

  • Adds conditional skipping of signature failures for self-issued chain CAs without an authority key identifier.
  • Adds positive and negative handshake regression tests.
  • Adds certificate fixtures, generation commands, and distribution entries.
File Description
tests/​api/​test_ssl_cert.h Declares and registers the regression tests.
tests/​api/​test_ssl_cert.c Tests tolerated extra roots and rejected bad signatures.
src/​internal.c Adds the alternate-chain root-skipping logic.
certs/​intermediate/​server-chain-alt-same-key-ecc.pem Negative chain fixture retaining the trusted key.
certs/​intermediate/​server-chain-alt-same-dn-rsa.pem Chain fixture with an extra same-name RSA root.
certs/​intermediate/​server-chain-alt-same-dn-int-ecc.pem Negative chain fixture with a non-self-issued CA.
certs/​intermediate/​server-chain-alt-same-dn-ecc.pem Chain fixture with an extra same-name ECC root.
certs/​intermediate/​server-chain-alt-same-dn-akid-ecc.pem Negative chain fixture carrying an authority key identifier.
certs/​intermediate/​include.am Includes the new fixtures in source distributions.
certs/​intermediate/​genintcerts.sh Generates the new certificates and chains.
certs/​intermediate/​ca-ecc-same-key-cert.pem Bad-signature CA fixture using the trusted key.
certs/​intermediate/​ca-ecc-same-dn-rsa-cert.pem Same-name root fixture using an RSA key.
certs/​intermediate/​ca-ecc-same-dn-int-cert.pem Non-self-issued CA fixture.
certs/​intermediate/​ca-ecc-same-dn-cert.pem Same-name root fixture using a different ECC key.
certs/​intermediate/​ca-ecc-same-dn-akid-cert.pem Same-name root fixture with an authority key identifier.

Review effort: Balanced

Comment thread src/internal.c Resolved
Comment thread src/internal.c Resolved
Comment thread tests/api/test_ssl_cert.c Resolved
@Frauschi

Copy link
Copy Markdown
Member Author

@claude review

@claude claude 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.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Comment thread src/internal.c Resolved

@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 #12077

Scan targets checked: wolfcrypt-src, wolfcrypt-bugs, wolfssl-src, wolfssl-bugs
Not reviewed (no scan target covers them): certs/intermediate/ca-ecc-same-dn-akid-cert.pem, certs/intermediate/ca-ecc-same-dn-akid-name-cert.pem, certs/intermediate/ca-ecc-same-dn-cert.pem, certs/intermediate/ca-ecc-same-dn-int-cert.pem, certs/intermediate/ca-ecc-same-dn-rsa-cert.pem, certs/intermediate/ca-ecc-same-key-cert.pem, certs/intermediate/genintcerts.sh, certs/intermediate/include.am, certs/intermediate/server-chain-alt-same-dn-akid-ecc.pem, certs/intermediate/server-chain-alt-same-dn-akid-name-ecc.pem, certs/intermediate/server-chain-alt-same-dn-ecc.pem, certs/intermediate/server-chain-alt-same-dn-int-ecc.pem, certs/intermediate/server-chain-alt-same-dn-rsa.pem, certs/intermediate/server-chain-alt-same-key-ecc.pem, tests/api/test_ssl_cert.h
Coverage: 4 of 4 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: Max

With WOLFSSL_ALT_CERT_CHAINS a chain CA that fails with ASN_NO_SIGNER_E
or ASN_SELF_SIGNED_E is skipped, as long as the peer certificate still
verifies to a trusted CA. An extra CA that carries no Authority Key
Identifier and shares its issuer name with a trusted CA is looked up by
name, finds that trusted CA and then fails with ASN_SIG_CONFIRM_E, or
with ASN_SIG_OID_E when the key types differ. Those errors aborted the
handshake even in alternate chain mode.

NSS can send such a chain: its own leaf and intermediate followed by the
peer's trust anchor from another PKI. RFC 8446 section 4.4.2 asks
implementations to tolerate extraneous certificates.

Treat both signature errors like the missing signer case when the chain
CA is self-issued, has no AKID, and the CA found for it has a different
public key. Only an error from parsing the chain CA counts, not one from
its OCSP or CRL check. A tampered intermediate, or a tampered copy of a
trusted root found by its own SKID, still fails on its own signature.
A CA with an AKID names its issuer, so a bad signature still fails the
handshake, as tests/test-fails.conf expects for
server-cert-rsa-badsig.pem. DecodedCert gains extAuthKeyIdPresent for
this, since extAuthKeyIdSet only records a key identifier and an AKID
with just issuer and serial would otherwise count as absent. Requiring a found issuer keeps out the
ASN_SIG_OID_E that DecodeCert returns when signatureAlgorithm differs
from the TBS signature; the original ASN decoder sets isCA before that
check, so such a malformed CA would otherwise be skipped. The skipped
certificate is not added to the certificate manager, so it never becomes
trusted and the peer certificate still has to verify on its own.

Add ECC test chains, generated by genintcerts.sh from existing keys,
that each end in an extra CA named after ca-ecc-cert.pem: roots with an
ECC and an RSA key and no key ids, a root with the key and SKID of
ca-ecc-cert.pem but signed by another key, roots with an AKID naming
ca-ecc-cert.pem by key id and by issuer and serial, and a CA that is not
self-issued. API tests expect the
first two to pass on an alternate chain when enabled and otherwise to
fail with ASN_SIG_CONFIRM_E and ASN_SIG_OID_E respectively. The other
four, and server-cert-rsa-badsig.pem whose chain CA carries an AKID,
fail with ASN_SIG_CONFIRM_E in both modes. The tests set
WOLFSSL_VERIFY_PEER on the client, since builds with
OPENSSL_COMPATIBLE_DEFAULTS default to no peer verification. They need WOLFSSL_PEM_TO_DER for the
PEM fixtures and are skipped with WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION,
where Security.framework revalidates the chain.
@Frauschi
Frauschi force-pushed the alt_chain_same_dn_root branch from d3815de to b2322fd Compare November 10, 2026 14:50
@Frauschi Frauschi assigned wolfSSL-Bot and unassigned Frauschi Nov 10, 2026
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