THRIFT-6233: Use the peer-address matcher in TSSLServerSocket on every Python - #3839
Merged
Merged
Conversation
slachiewicz
force-pushed
the
THRIFT-6233
branch
from
September 14, 2026 09:44
79be3ca to
42d6fb0
Compare
This comment was marked as resolved.
This comment was marked as resolved.
slachiewicz
marked this pull request as ready for review
September 15, 2026 21:08
slachiewicz
marked this pull request as draft
September 16, 2026 13:12
slachiewicz
force-pushed
the
THRIFT-6233
branch
from
September 16, 2026 13:49
42d6fb0 to
228341e
Compare
slachiewicz
force-pushed
the
THRIFT-6233
branch
from
September 17, 2026 18:51
228341e to
2265d72
Compare
…y Python Client: py TSSLServerSocket checks a client certificate against the address the connection came from. On Python 3.12 and later it used sslcompat.match_peer_ipaddress. On 3.11 and earlier it used ssl.match_hostname. The two disagree. Only the former reduces an IPv4-mapped peer (THRIFT-6201). Only the latter falls back to the commonName when the certificate has no subjectAltName. A dual-stack listener reports an IPv4 client as ::ffff:127.0.0.1, so a certificate that carries 127.0.0.1 was accepted on 3.12 and refused on 3.10. THRIFT-3660 hid that in 2016 by listing the mapped address in client_v3.crt. THRIFT-6275 removed that entry, because Go 1.27 refuses to load a certificate with one. Since then the cross-test Python server, which listens dual-stack with client_v3.crt as its CA, refuses every IPv4 client on 3.11 and earlier. The server only matches an IP address, so match_peer_ipaddress is now its default on every version. The check runs whenever cert_reqs asks for a client certificate. It looks only at IP subjectAltName records. Which subjects may connect is the application's decision, made in a validate_callback; the docstring now shows one. TSSLSocket on the client side is unchanged. The backports.ssl_match_hostname branch in sslcompat, and the ValueError that named it, are removed. THRIFT-6265 already dropped the setup.py dependency. The library requires Python 3.10, so nothing below 3.5 can reach them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
slachiewicz
force-pushed
the
THRIFT-6233
branch
from
September 18, 2026 23:11
2265d72 to
e2cd212
Compare
slachiewicz
marked this pull request as ready for review
September 18, 2026 23:14
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.
JIRA: THRIFT-6233
Client: py
TSSLServerSocketchecks a client certificate against the address the connection came from, whenevercert_reqsasks for a certificate. Which function did the check depended on the Python version. Python 3.12 and later usedsslcompat.match_peer_ipaddress. Python 3.11 and earlier usedssl.match_hostname. The two disagree. Only the former reduces an IPv4-mapped peer (THRIFT-6201). Only the latter falls back to the commonName when the certificate has no subjectAltName. A dual-stack listener (host=None) reports an IPv4 client as::ffff:127.0.0.1. So a certificate that carries127.0.0.1was accepted on 3.12 and refused on 3.10. THRIFT-3660 hid that in 2016 by listing the mapped address inclient_v3.crt. #3857 removed that entry, because Go 1.27 refuses to load a certificate with one. Since then the cross-test Python server, which listens dual-stack withclient_v3.crtas its CA, refuses every IPv4 client on Python 3.11 and earlier.The server only matches an IP address, so
match_peer_ipaddressis now its default on every version. The check stays on by default and looks only at IP subjectAltName records. An IPv4-mapped peer matches the plain address on every version. A certificate without an IP subjectAltName is refused, wheressl.match_hostnamecompared the commonName with the address string. DNS records are not matched, because a server has no name for its client. To decide which subjects may connect, pass avalidate_callback. It receives thegetpeercert()dictionary and the peer address. The docstring shows a callback that refuses on the subject.TSSLSocketon the client side is unchanged.The
backports.ssl_match_hostnamebranch insslcompat._optional_dependenciesand theValueErrorinTSSLServerSocket.__init__that named it are removed. #3863 (THRIFT-6265) already dropped thesetup.pydependency. The library requires Python 3.10, so nothing below 3.5 reaches them.The tests drive
TSSLServerSocket.accept()under the running interpreter:client_v3.crtis accepted.client.crt, which has no subjectAltName, is refused.client_v3.crt, which no longer carries a mapped entry. This is the cross-test server's configuration.lib/py/README.mdrecords the change for 0.25.0.Verified:
test/test_sslsocket.pypasses against this branch on Python 3.10, 3.11, 3.12, 3.13 and 3.14. Against master's library, the default-callback test and the dual-stack test fail on 3.10 and 3.11.flake8 --config setup.cfgreports the same 19 pre-existing E501 lines as master and none in the new code.This change was created with AI assistance.