Skip to content

Check CA ExtKeyUsage for issuers from the CertManager - #11873

Open
sameehj wants to merge 1 commit into
wolfSSL:masterfrom
sameehj:fix-ca-ext-key-usage-certmanager
Open

sameehj wants to merge 1 commit into
wolfSSL:masterfrom
sameehj:fix-ca-ext-key-usage-certmanager

Conversation

@sameehj

@sameehj sameehj commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Description

ProcessPeerCerts() checks the Extended Key Usage of CA certificates against the TLS purpose (serverAuth when verifying a server, clientAuth when verifying a client), but only for CAs the peer sends in its Certificate message. When the peer sends only its leaf and the issuing CA is already loaded in the CertManager, that CA's Extended Key Usage is not checked. The same chain is therefore rejected with EXTKEYUSE_AUTH_E when the intermediate is sent and accepted when it is omitted.

This change makes the result independent of which CAs the peer sends:

  • Signer gains an extExtKeyUsageSet bit, set by FillSigner(), so an absent extension can be told apart from one that grants none of the known purposes.
  • CheckSignerExtKeyUsage() walks from the leaf's issuer up to the self-signed trust anchor and applies the TLS purpose to every CA on the way. The trust anchor stays exempt, as in CheckChainCAExtKeyUsage(). The walk reuses the name constraints ancestor lookup, now exported as wolfssl_local_FindSignerByAkidOrName(), with the same cycle guard and WOLFSSL_MAX_CHAIN_DEPTH limit.
  • The check runs after the leaf's own key usage checks. A verify callback can override it as it can the other leaf errors. It is skipped when a chain verify callback is installed, when verification is disabled, and for a trusted peer certificate (WOLFSSL_TRUST_PEER_CERT), whose chain is not used.
  • With IGNORE_NAME_CONSTRAINTS the Signer has no issuer lookup data, so only the leaf's direct issuer is checked.

Testing

test_wolfSSL_chain_ca_ext_key_usage gains a leafOnly option, where the peer sends only the leaf and the CAs are loaded into the verifier. New cases:

  • depth 1: codeSigning and clientAuth CA rejected, and serverAuth, no extension and anyExtendedKeyUsage accepted, when verifying a server
  • depth 1: codeSigning and serverAuth CA rejected, and clientAuth and no extension accepted, when verifying a client
  • depth 2, with the restricted CA above an unrestricted one and neither sent, for server and client authentication
  • a verify callback overriding the result for a leaf-only chain, and one that accepts only EXTKEYUSE_AUTH_E, showing that the callback is given that error
  • a self-signed codeSigning trust anchor with a leaf-only chain, which stays accepted

Built and run with the default configure flags plus cert generation, and with each of OPENSSL_EXTRA, OPENSSL_EXTRA + WOLFSSL_CHAIN_VERIFY_CB, IGNORE_NAME_CONSTRAINTS, WOLFSSL_ASN_ORIGINAL, WOLFSSL_ALT_CERT_CHAINS with CRL/OCSP and status request, WOLFSSL_TRUST_PEER_CERT, and NO_SKID. A trusted peer leaf whose issuer name matches a restricted CA in the CertManager still connects with the example client (-E). The new cases fail without the library change. The full --api suite passes in the default and OPENSSL_EXTRA builds.

NO_SKID note: the existing self-issued rollover cases in this test already fail on master with NO_SKID (ASN_SIG_CONFIRM_E); this change does not affect them.

Checklist

  • added tests
  • updated/added doxygen
  • updated appropriate READMEs
  • Updated manual and documentation

The CA Extended Key Usage check in ProcessPeerCerts() ran only for CA
certificates in the peer's Certificate message. When the peer sent just
its leaf, the issuing CA came from the CertManager and its Extended Key
Usage was not looked at, so the result depended on whether the peer
included the intermediate.

Record in the Signer whether the certificate had an Extended Key Usage
extension, and after the leaf checks walk every CA from the leaf's issuer
up to the self-signed trust anchor, applying the TLS purpose to each. The
walk uses the same AKID-or-name lookup as the name constraints check,
which is exported as wolfssl_local_FindSignerByAkidOrName(). Trusted peer
certificates are not checked, as their chain is not used.

Extend test_wolfSSL_chain_ca_ext_key_usage with leaf-only cases at depth
one and two for server and client authentication, verify callback
handling and a self-signed trust anchor.
Copilot AI balanced review requested due to automatic review settings October 23, 2026 10:37
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report

gcc-arm-cortex-m0plus

  • FLASH: .text +20 B (+0.0%, 70,447 B / 262,144 B, total: 27% used)

gcc-arm-cortex-m3

  • FLASH: .text +184 B (+0.1%, 130,901 B / 262,144 B, total: 50% used)

gcc-arm-cortex-m4

  • FLASH: .text +128 B (+0.1%, 210,012 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m4-crypto-only

  • FLASH: .text +64 B (+0.0%, 182,463 B / 262,144 B, total: 70% used)

gcc-arm-cortex-m4-dtls13

  • FLASH: .text +192 B (+0.1%, 194,392 B / 1,048,576 B, total: 19% used)

gcc-arm-cortex-m4-min-ecc

  • FLASH: .text +64 B (+0.1%, 67,673 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .text +192 B (+0.0%, 795,108 B / 1,048,576 B, total: 76% used)

gcc-arm-cortex-m4-pq

  • FLASH: .text +128 B (+0.0%, 311,780 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m4-rsa-only

  • FLASH: .text +192 B (+0.1%, 343,192 B / 1,048,576 B, total: 33% used)

gcc-arm-cortex-m4-sp-math

  • FLASH: .text +64 B (+0.1%, 67,673 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m4-tls12

  • FLASH: .text +192 B (+0.1%, 131,665 B / 262,144 B, total: 50% used)

gcc-arm-cortex-m4-tls13

  • FLASH: .text +192 B (+0.1%, 249,358 B / 262,144 B, total: 95% used)

gcc-arm-cortex-m7

  • FLASH: .text +128 B (+0.1%, 210,012 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m7-pq

  • FLASH: .text +192 B (+0.1%, 312,740 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m7-tls13

  • FLASH: .text +128 B (+0.1%, 249,358 B / 262,144 B, total: 95% used)

linuxkm-standard

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

Pending signers and restored caches can bypass issuer EKU checks, and repeated checks can invalidate certificate-specific callback overrides.

3 open issues
What changed in this PR

This PR extends TLS issuer Extended Key Usage checks to CAs loaded in the CertManager, aiming to make validation independent of which intermediates the peer sends.

Changes:

  • Records EKU extension presence on cached signers.
  • Walks issuer ancestors to enforce the TLS purpose while exempting self-signed trust anchors.
  • Adds leaf-only chain tests for server/client authentication, callback overrides and trust-anchor handling.
File Description
wolfssl/​wolfcrypt/​asn.h Adds signer EKU presence state and declares the shared issuer lookup.
wolfcrypt/​src/​asn.c Populates the new state and exposes the existing ancestor lookup.
tests/​api/​test_ssl_cert.c Extends the handshake harness and adds cached-issuer test cases.
src/​internal.c Adds issuer-chain EKU validation during peer certificate processing.

Review effort: Balanced

Comment thread src/internal.c
return EXTKEYUSE_AUTH_E;
}
#ifndef IGNORE_NAME_CONSTRAINTS
parent = wolfssl_local_FindSignerByAkidOrName(SSL_CM(ssl), NULL, ca);
Comment thread wolfssl/wolfcrypt/asn.h
byte extKeyUsage;
word16 maxPathLen;
WC_BITFIELD selfSigned:1; /* Own key verified the signature */
WC_BITFIELD extExtKeyUsageSet:1; /* EKU extension present */
Comment thread src/internal.c
!args->haveTrustPeer &&
#endif
!UsingChainVerifyCb(ssl)) {
ret = CheckSignerExtKeyUsage(ssl, args->dCert->ca);
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