Skip to content

Fix UTF-8 validation to reject invalid code points - #91

Merged
partim merged 3 commits into
NLnetLabs:mainfrom
sumleo:fix/utf8-validation
May 8, 2026
Merged

partim merged 3 commits into
NLnetLabs:mainfrom
sumleo:fix/utf8-validation

Conversation

@sumleo

@sumleo sumleo commented Feb 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes a soundness issue in UTF-8 string validation that could create invalid char values from malformed UTF-8 sequences, leading to undefined behavior.

Problem

The Utf8CharSet::next_char implementation used char::from_u32_unchecked without proper validation, accepting:

  • Surrogate code points (U+D800..U+DFFF)
  • Code points above maximum Unicode (>U+10FFFF)
  • Overlong UTF-8 encodings

This violated Rust safety guarantees and could cause memory corruption or process termination.

Solution

  • Replaced unsafe char::from_u32_unchecked with safe char::from_u32
  • Added validation for minimum encoding lengths to reject overlong sequences
  • char::from_u32 inherently rejects surrogates and out-of-range values

Testing

Added three test cases verifying rejection of:

  • Surrogate code points (U+D800, U+DFFF)
  • Overlong encodings (e.g., C0 80 for U+0000)
  • Above-maximum values (e.g., U+110000)

All existing tests continue to pass.

Impact

This is a critical security fix that prevents undefined behavior from untrusted input (e.g., X.509 certificates with UTF8String fields).

sumleo and others added 3 commits February 15, 2026 21:00
Replace unsafe char::from_u32_unchecked with safe char::from_u32 to
properly validate Unicode scalar values. This prevents undefined behavior
from invalid characters created from:

- Surrogate code points (U+D800..U+DFFF)
- Code points above maximum Unicode (>U+10FFFF)
- Overlong UTF-8 encodings

Added validation checks for minimum encoding lengths to reject overlong
sequences. Added tests to verify rejection of all invalid cases.

Fixes a soundness issue where invalid UTF-8 byte sequences could create
invalid char values, leading to undefined behavior.
@partim
partim merged commit 7a37293 into NLnetLabs:main May 8, 2026
12 checks passed
partim added a commit that referenced this pull request Jun 8, 2026
New

* Added `RestrictedString::take_opt_from`. ([#90])

Improvements

* `BIT_STRING` parsing now checks that the unused bits are zero in CER and
  DER modes. ([#97])

Bug fixes

* Fixed `Utf8String` potentially accepting invalid UTF-8. ([#91] by [@sumleo])
* Fixed a panic in `Unsigned::from_bytes` when the input is all zero.
  ([#92] by [@sumleo])
* Fixed incorrect bounds check in `BitString::bit`. ([#93] by [@sumleo])
* Added character set validation to `FromStr` impl for `NumericString`,
  `PrintableString`, and `Ia5String`. ([#95] by [@sumleo])
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