-
-
Notifications
You must be signed in to change notification settings - Fork 32k
bpo-18233: Add SSLSocket.get_verified_chain() and SSLSocket.get_unverified_chain() #17938
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
4f88c3d
to
8586656
Compare
I like that there's the option to get both the raw chain and the verified chain – these are different things and both are important for different purposes. But the docs should be clearer about the difference. Maybe fetching the verified chain should only be supported when building against openssl 1.1.1? That would simplify this patch a lot, and follow the general trend of trying to get rid of custom cert verification logic in the ssl module. For the unverified chain, the openssl docs say:
I think this is confusing, and we should hide the confusing bit from python users. My preference would be for the python wrapper to always return the complete cert chain, including the leaf. So when necessary, the wrapper should manually call |
Thanks for taking a look so promptly.
I'm very happy to do that if it's acceptable to only partially support openssl 1.0.2 and throw an exception if
I definitely agree, I'll implement it soon 👍 |
I implemented it in df65d40 but I've changed my mind as it makes using |
OpenSSL 1.0.2 and 1.1.0 have reached EOL and are no longer supported by upstream. Please don't add workarounds / backports for these versions. Just make sure that Python can still be compiled with 1.0.2. IMO there should be two new methods, one to get the raw peer cert chain and another one to get the "verified" chain. I put "verified" in quotes because the term is misleading. Internally OpenSSL always builds and validates the chain, even with I also like to get rid of |
Doc/library/ssl.rst
Outdated
Returns certificate chain for the peer. If no chain is provided, returns | ||
None. Otherwise returns a tuple of dicts containing information about the | ||
certificates. The chain starts with the leaf certificate and ends with the | ||
root certificate. If called on the client side, the leaf certificate is the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not necessarily correct. SSL_get_peer_cert_chain()
returns whatever the client sends. It may just be the EE cert (end entity), EE+intermediates, EE+intermediate+root, EE with intermediates for primary and alternative chains, or whatever the admin for the site has configured. I guess the peer chain can even include unrelated junk.
It's also worth mentioning that the chain is not available with TLS session resumption.
Modules/_ssl.c
Outdated
peer_chain = SSL_get0_verified_chain(self->ssl); | ||
long ret = SSL_get_verify_result(self->ssl); | ||
if (ret != X509_V_OK) { | ||
#ifdef SSL_R_CERTIFICATE_VERIFY_FAILED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SSL_R_CERTIFICATE_VERIFY_FAILED
is always defined on 1.1.0+.
Modules/_ssl.c
Outdated
return NULL; | ||
#endif | ||
} else { | ||
peer_chain = SSL_get_peer_cert_chain(self->ssl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
peer_chain
can be NULL.
Modules/_ssl.c
Outdated
if (self->socket_type == PY_SSL_SERVER) { | ||
X509 *peer_cert = SSL_get_peer_certificate(self->ssl); | ||
if (peer_cert != NULL) | ||
sk_X509_insert(peer_chain, peer_cert, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
peer_chain
can be NULL here.
A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated. Once you have made the requested changes, please leave a comment on this pull request containing the phrase |
By the way LibreSSL doesn't have |
Thanks for the review @tiran!
That makes sense. I have two follow up questions:
|
|
5366c81
to
bf6e309
Compare
Thanks for the quick reply. I've made the changes and tested them with both OpenSSL 1.0 and 1.1 and it behaves as you propose. For the sake of the bot: I have made the requested changes; please review again |
Thanks for making the requested changes! @tiran: please review the changes made to this pull request. |
You know, looking at this again today, I'd suggest naming the two methods: |
@tiran Sorry to pester you, but could you take another look when you get a chance? |
@tiran Hi again, would you be able to take another look at this? I'd like to get it in before the 3.9 feature freeze if possible. |
I stumbled on this pull request in my search for exactly this functionality. Is there anything I can do to help get this across the line? |
d0b6a5d
to
3d21652
Compare
I've just rebased to resolve a conflict from the clinic generated hash at the end of I'm also still very keen to get this in so I'm happy to do anything that is needed. |
Just an extra push for this PR that I am really eager to see merged as well |
I poked @tiran about this PR on IRC just now, and he said:
Hmm, and this makes me wonder: @tiran, do you want any help on finishing and landing the certificate object code? It seems like some folks here would be eager to help... |
3d21652
to
3a6435a
Compare
Based on the patch provided by Christian Heimes (christian.heimes) and updated by Mariusz Masztalerczuk (mmasztalerczuk).
3a6435a
to
1f8dfd6
Compare
Hey @tiran, has there been any progress with the new certificate objects? I'm still happy to help out if it's useful. |
@chrisburr I've been looking into this. https://github.com/python/cpython/blob/main/Modules/_ssl/cert.c has the new certificate class as far as I can tell. If you can get an |
It seems another PR got merged that provides a similar functionality: #109113 |
Based on the patch provided by Christian Heimes (christian.heimes) and updated by Mariusz Masztalerczuk (mmasztalerczuk). Updated to use
SSL_get0_verified_chain
in OpenSSL 1.1 as suggested by Jörn Heissler (joernheissler).Tested with both OpenSSL 1.0.2 and 1.1.1 using the included test and:
https://bugs.python.org/issue18233