fix(tls): drop the root label from FQDNs in the certificate path - #8340
Open
ArockiaRajamanickam wants to merge 3 commits into
Open
fix(tls): drop the root label from FQDNs in the certificate path#8340ArockiaRajamanickam wants to merge 3 commits into
ArockiaRajamanickam wants to merge 3 commits into
Conversation
Visiting https://example.com./ produced a certificate for 'example.com.' and sent a trailing dot in the SNI HostName, so hostname verification failed with "hostname 'example.com.' doesn't match 'example.com'". Python's idna codec keeps the trailing dot, so nothing normalised it away. Remove it where a hostname enters the TLS and certificate path: in _ip_or_dns_name(), which feeds the generated certificate's SANs and the CN derived from them, and on the SNI sent upstream, which RFC 6066 section 3 says must not carry a trailing dot. Fixes mitmproxy#2989
…x-2989-trailing-dot # Conflicts: # CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2989.
Python's
idnacodec keeps a trailing dot ('example.com.'.encode('idna')isb'example.com.'), so nothing along the TLS path ever normalised it away. Two consequences, both reproduced on current main:The generated certificate carries the dot.
_ip_or_dns_name()feeds the SANs, and the CN is then derived from the first SAN, so a request forexample.com.produced:which is not what a client verifying
example.comlooks for — the error in the issue.The SNI carries it too.
server.sni.encode("idna")is used both as thetlsext_host_namesent upstream and as theX509_VERIFY_PARAM_set1_hostverification parameter. RFC 6066 section 3 is explicit that the HostName "MUST NOT" include a trailing dot, so this was also sending a non-conformant SNI upstream.The change adds
_remove_trailing_dot()and applies it at those two points, which is the "use the dot-less version consistently where applicable" you asked for. After it:Scope. I left the
idnacall incerts._fix_legacy_sans()alone. It is the deprecated string-list path for mitmproxy 10.1 and below and is marked# pragma: no cover, so normalising there seemed like widening the diff into dead code rather than fixing the reported bug. Happy to include it if you would rather it were consistent everywhere.Behaviour change worth naming. A certificate for a trailing-dot request is now issued for the dot-less name. That is the point of the fix, but it does mean generated certs differ for those hosts, and a cached cert from a previous run keyed on the old name will not be reused.
Tests. Three added: a unit test for the helper, one for
_ip_or_dns_namecovering the trailing-dot, IDN, plain and IP cases, andtest_get_cert_trailing_dot, which goes throughTlsConfig.get_cert()with a trailing-dot SNI and server address and asserts both the CN and the SANs come out dot-less. All three fail on main — the integration one withassert 'example.com.' == 'example.com'.test_tlsconfig.py,test_certs.pyandproxy/layers/test_tls.pytogether are 90 passed. Two failures intest_tlsconfig.py(test_configure_tls_version,test_configure_ciphers) also fail on unmodified main in my environment — they are about SSL3/TLS1 support in the local OpenSSL, unrelated to this change.ruff checkandruff format --checkare clean, andmypyreports no errors intlsconfig.py(the errors it does report are pre-existing and in other files).I used an AI assistant while working on this. The reproduction, the before/after output above and the check that those two failures pre-date the change are mine.