Enforce Extended Key Usage on chain-supplied intermediate CAs - #11145
Enforce Extended Key Usage on chain-supplied intermediate CAs#11145embhorn wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR tightens TLS certificate-chain validation by enforcing RFC 5280 Extended Key Usage (EKU) constraints not just on the peer leaf certificate, but also on chain-supplied intermediate CA certificates validated in ProcessPeerCerts(). It also adds an OpenSSL-compat verify-result mapping for this failure and introduces a targeted regression test.
Changes:
- Enforce
serverAuth/clientAuthEKU purpose checks on chain-supplied intermediate CAs during peer authentication, failing withEXTKEYUSE_AUTH_E(unlessIGNORE_KEY_EXTENSIONSis defined). - Add OpenSSL-compatibility reporting via
WOLFSSL_X509_V_ERR_INVALID_PURPOSEand mapEXTKEYUSE_AUTH_Eto it. - Add
test_wolfSSL_chain_ca_ext_key_usage()to cover allowed/denied intermediate-CA EKU scenarios in both server- and client-auth directions.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
wolfssl/ssl.h |
Adds WOLFSSL_X509_V_ERR_INVALID_PURPOSE verify-result code. |
wolfcrypt/src/asn.c |
Updates IGNORE_KEY_EXTENSIONS documentation to include chain-CA EKU enforcement. |
src/internal.c |
Implements chain-CA EKU purpose check and adds OpenSSL reason string for the new verify-result code. |
src/x509_str.c |
Maps EXTKEYUSE_AUTH_E to WOLFSSL_X509_V_ERR_INVALID_PURPOSE for compatibility-layer error reporting. |
tests/api/test_ssl_cert.c |
Adds a memio-based regression test that generates CA/leaf certs with different EKUs and validates handshake outcomes. |
tests/api/test_ssl_cert.h |
Registers the new API test in the ssl_cert group. |
tests/api.c |
Updates error-string test “missing ranges” to account for the new X509 verify-result value. |
ChangeLog.md |
Documents the security fix and behavior change, including the new verify-result code. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| #ifdef OPENSSL_EXTRA | ||
| if (args->certIdx > args->untrustedDepth) { | ||
| args->untrustedDepth = (char)args->certIdx + 1; |
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #11145
Scan targets checked: wolfcrypt-bugs, wolfcrypt-rs-bugs, wolfcrypt-src, wolfssl-bugs, wolfssl-src
Findings: 3
3 finding(s) posted as inline comments (see file-level comments below)
This review was generated automatically by Fenrir. Findings are non-blocking.
| * Extended Key Usage must not authenticate this peer, | ||
| * whether or not the certificate manager already | ||
| * holds it. */ | ||
| ret = CheckChainCAExtKeyUsage(ssl, args->dCert); |
There was a problem hiding this comment.
🔵 [Low] Chain CA purpose check applies only to transmitted CAs, evadable by omitting the intermediate · Certificate and trust chain validation bypass
CheckChainCAExtKeyUsage() runs only inside the transmitted-chain loop. A peer that omits a purpose-constrained intermediate the verifier can already resolve from its certificate manager (operator-loaded, or cached earlier by AddCA(..., WOLFSSL_CHAIN_CA, ...)) gets the leaf accepted with no purpose check.
Related known finding #1814 (similar but distinct): Both concern extended-key-usage enforcement in ProcessPeerCerts, but #1814 suppresses peer usage checks under OPENSSL_EXTRA plus verifyNone, whereas this check is skipped when an intermediate is locally resolved rather than transmitted. The faulting operation, root cause, and required patch differ.
Fix: Enforce the purpose on the Signer resolved during leaf validation too, adding an "EKU present" sentinel to Signer.extKeyUsage as Signer.keyUsage already uses 0xFFFF.
|
|
||
| if ((cert->extExtKeyUsage & (EXTKEYUSE_ANY | purpose)) == 0) { | ||
| WOLFSSL_MSG("Chain CA ExtKeyUse doesn't allow TLS peer authentication"); | ||
| return EXTKEYUSE_AUTH_E; |
There was a problem hiding this comment.
🔵 [Low] Purpose check rejects extraneous chain certificates that are not in the validated path · Cryptographic correctness
The check is applied to every CA the peer transmits, not only to certificates in the leaf's certification path. A peer that bundles an extraneous but locally verifiable CA (timestamping or OCSP-signing sub-CA of the same root) now gets a fatal bad_certificate alert, although RFC 8446 4.4.2 permits extraneous certificates.
Related known finding #5814 (similar but distinct): Both concern certificate usage-constraint enforcement during peer processing, but #5814 omits leaf client keyUsage validation for static-RSA suites, while this applies CA extended-key-usage validation to extraneous transmitted certificates. They involve different certificate roles, operations, root causes, and fixes.
Fix: Limit enforcement to certificates on the leaf's issuer path, or set skipAddCA for an extraneous purpose-mismatched CA instead of failing the handshake.
| !defined(NO_TLS) && !defined(NO_SHA256) && !defined(NO_ASN_TIME) && \ | ||
| defined(WOLFSSL_CERT_GEN) && defined(WOLFSSL_CERT_EXT) && \ | ||
| defined(USE_CERT_BUFFERS_2048) && !defined(IGNORE_KEY_EXTENSIONS) | ||
| static const test_eku_case cases[] = { |
There was a problem hiding this comment.
⚪ [Info] New chain-EKU test covers only depth-1 intermediates and no verify-callback override · Missing edge-case coverage on a function the PR also changed
Every case builds a two-certificate chain, so enforcement at chain depth greater than one is unexercised, and no case installs a verify callback — the override path that the new comment in ProcessPeerCertAddPendingCA relies on for CSR v2 correctness is untested.
Fix: Add a three-level chain case with the constrained CA at depth 2, and a case whose verify callback overrides EXTKEYUSE_AUTH_E.
|
Description
The peer certificate is checked for the serverAuth/clientAuth EKU, but the intermediate CAs sent with it were not. A CA constrained to another purpose by a critical EKU, a code signing sub-CA for example, could issue a serverAuth leaf for any hostname and wolfSSL would complete the handshake.
ProcessPeerCerts() now applies the same purpose rule to every chain CA it validates and fails with EXTKEYUSE_AUTH_E. An absent extension and anyExtendedKeyUsage leave all purposes valid per RFC 5280 4.2.1.12, and a self-signed certificate is exempt since it can only serve as an operator-loaded trust anchor. IGNORE_KEY_EXTENSIONS opts out, as it already did for the peer certificate.
Fixes zd22309
Testing
Added
test_wolfSSL_chain_ca_ext_key_usage()Checklist