Skip to content

percent decode in URIs and enforce LDH - #12003

Open
sebastian-carpenter wants to merge 1 commit into
wolfSSL:masterfrom
sebastian-carpenter:perc-uri
Open

sebastian-carpenter wants to merge 1 commit into
wolfSSL:masterfrom
sebastian-carpenter:perc-uri

Conversation

@sebastian-carpenter

@sebastian-carpenter sebastian-carpenter commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Description

Percent-decode the URI host before it is compared against 'Name Constraints'. Previously the comparison was done over the raw bytes.

Fix

  • Decode (RFC 5280 §7.4): escaped unreserved characters in a reg-name host are decoded before comparison. Any other escape, or a malformed one, rejects the host.
  • Host characters: the decoded host may contain only RFC 3986 unreserved characters: letters, digits, -, ., _ and ~.

The constraint base is never decoded, and IP literals in brackets aren't either.

Behavior

Constraint is host.example.com:

SAN host Permitted Excluded Changed?
host.example.com accept reject no
other.example.com reject accept no
h%6Fst.example.com accept reject yes
h_st.example.com, h~st.example.com, h%5Fst.example.com reject accept no
h!st.example.com and other sub-delims reject reject yes
Other invalid host characters (\, space, NUL, non-ASCII) reject reject yes
Reserved or non-ASCII escapes (%2F, %40, %25, %00, %C3%A9) reject reject yes
Malformed escapes (%ZZ, %6Z, %6, %) reject reject yes
Decoded host over 254 octets reject reject yes
IP host (12.31.2.3, [2001:db8::1]) reject reject no
Decodes to an IP (%31%32.31.2.3) reject reject yes
No authority (urn:example:host.example.com) reject reject no

Constraint base is malformed, SAN host is valid:

Base Permitted Excluded
h%6Fst.example.com, example..com, ., empty reject accept

These behave as they did before this branch. Such a base can't match a valid host, and RFC 5280 puts the FQDN requirement on the CA. So a malformed excluded base silently excludes nothing.

Host characters

Strict LDH (RFC 1123) would reject _, which real hosts use (SPIFFE trust domains, my_host.example.com). Rejecting it would make any URI name constraint, even an unrelated excluded-only one, fail the whole chain. The accepted set is therefore exactly RFC 3986 unreserved, the same set that percent-decoding accepts, so %5F and %7E decode to characters that are then allowed. Sub-delims (! $ & ' ( ) * + , ; =) are valid in an RFC 3986 reg-name but are not DNS host characters, so they are rejected.

For example, https://my_host.example.com/ still matches a permitted .example.com.

Tests

  • test_wolfssl_local_MatchUriNameConstraint (tests/api/test_asn.c): matcher rows for decoding, malformed and reserved escapes, _ and ~ hosts raw and escaped, sub-delim hosts, decoded length limits, ACE hosts and malformed bases.
  • test_wolfSSL_NAME_CONSTRAINTS_uri (tests/api/test_ossl_x509_ext.c): escaped, malformed and invalid hosts under the permitted .wolfssl.com from a real certificate.
  • test_wolfSSL_NAME_CONSTRAINTS_check_name (tests/api/test_ossl_x509_ext.c):
    • h%6Fst under a permitted and an excluded host.example.com
    • URIs without a DNS host under an excluded constraint
    • h%5Fst.example.com passing an unrelated excluded constraint
    • h%6Fst.example.com as a malformed base in both directions
  • tests/unit-mcdc/test_asn_fault_whitebox.c: updated for the new GetUriHost() signature.

Fixes zd#22727

Testing

Run ./configure --enable-opensslall to pull in the extra tests otherwise default covers the non-openssl stuff. The changed tests can be run with: ./tests/unit.test -test_wolfssl_local_MatchUriNameConstraint -test_wolfSSL_NAME_CONSTRAINTS_uri -test_wolfSSL_NAME_CONSTRAINTS_check_name.

For mc-dc build with ./configure --enable-all --enable-static --disable-shared CPPFLAGS=-DWOLFSSL_TEST_STATIC_BUILD. Run the tests with ./tests/unit-mcdc/run-whitebox-smoke.sh.

Checklist

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

@sebastian-carpenter sebastian-carpenter self-assigned this Nov 4, 2026
Copilot AI balanced review requested due to automatic review settings November 4, 2026 21:46

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

The no-escape URI host path bypasses URI_HOST_MAX_SZ, allowing an oversized host that is rejected in its equivalent escaped form, and needs the same bound plus an unescaped boundary test.

1 open issue
What changed in this PR

This PR normalizes URI hosts before certificate name-constraint matching and restricts host characters to letters, digits, hyphens, and dots.

Changes:

  • Decode escaped unreserved host characters and reject malformed or disallowed escapes.
  • Add matcher and OpenSSL-compatible API tests for normalization and invalid hosts.
  • Update white-box tests for the host parser’s new buffer parameter.
File Description
wolfcrypt/​src/​asn.c Adds host percent-decoding and character validation before constraint matching.
tests/​unit-mcdc/​test_asn_fault_whitebox.c Supplies the new host buffer to parser tests.
tests/​api/​test_ossl_x509_ext.c Tests encoded and invalid hosts under permitted and excluded constraints.
tests/​api/​test_asn.c Adds decoding, host-length, invalid-character, and malformed-base cases.

Review effort: Balanced

Comment thread wolfcrypt/src/asn.c Resolved
@github-actions

github-actions Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report · Explore what changed →

gcc-arm-cortex-m0plus

  • FLASH: .text +252 B (+0.4%, 71,447 B / 262,144 B, total: 27% used)

gcc-arm-cortex-m3

  • FLASH: .text +252 B (+0.2%, 132,481 B / 262,144 B, total: 51% used)

gcc-arm-cortex-m4

  • FLASH: .text +256 B (+0.1%, 209,804 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m4-baremetal

  • FLASH: .text +256 B (+0.3%, 74,231 B / 262,144 B, total: 28% used)

gcc-arm-cortex-m4-crypto-only

  • FLASH: .text +256 B (+0.1%, 182,547 B / 262,144 B, total: 70% used)

gcc-arm-cortex-m4-dtls13

  • FLASH: .text +256 B (+0.1%, 196,760 B / 1,048,576 B, total: 19% used)

gcc-arm-cortex-m4-min-ecc

  • FLASH: .text +256 B (+0.4%, 68,697 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .text +192 B (+0.0%, 802,372 B / 1,048,576 B, total: 77% used)

gcc-arm-cortex-m4-pkcs7

  • FLASH: .text +256 B (+0.1%, 223,636 B / 262,144 B, total: 85% used)

gcc-arm-cortex-m4-pq

  • FLASH: .text +256 B (+0.1%, 313,680 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m4-rsa-only

  • FLASH: .text +256 B (+0.1%, 344,208 B / 1,048,576 B, total: 33% used)

gcc-arm-cortex-m4-sp-math

  • FLASH: .text +256 B (+0.4%, 68,697 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m4-tls12

  • FLASH: .text +256 B (+0.2%, 133,265 B / 262,144 B, total: 51% used)

gcc-arm-cortex-m4-tls13

  • FLASH: .text +256 B (+0.1%, 250,402 B / 262,144 B, total: 96% used)

gcc-arm-cortex-m7

  • FLASH: .text +256 B (+0.1%, 209,804 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m7-pq

  • FLASH: .text +256 B (+0.1%, 314,512 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m7-tls13

  • FLASH: .text +256 B (+0.1%, 250,402 B / 262,144 B, total: 96% used)

stm32-sim-stm32h753

  • FLASH: .text +448 B (+0.2%, 205,356 B / 2,097,152 B, total: 10% used)

zephyr-frdm_rw612

  • FLASH: datas +16 B, log_const_area -8 B, rodata +36 B, text +11,960 B (+4.2%, 294,468 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)

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

@sebastian-carpenter

sebastian-carpenter commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor Author

Jenkins retest this please.

@sebastian-carpenter

Copy link
Copy Markdown
Contributor Author

Jenkins retest this please.

@SparkiDev

Copy link
Copy Markdown
Contributor

@claude review

Comment thread wolfcrypt/src/asn.c Resolved
@sebastian-carpenter

Copy link
Copy Markdown
Contributor Author

relaxed restriction on both '_' and '~'

@sebastian-carpenter sebastian-carpenter removed their assignment Nov 12, 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