This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Add getters for all SSLContext internal configuration
Type: enhancement Stage: needs patch
Components: SSL Versions: Python 3.8
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: alex, christian.heimes, dstufft, janssen, njs
Priority: normal Keywords:

Created on 2017-12-18 09:41 by njs, last changed 2022-04-11 14:58 by admin.

Messages (8)
msg308533 - (view) Author: Nathaniel Smith (njs) * (Python committer) Date: 2017-12-18 09:41
Suppose you're writing a library that allows users to make or accept SSL/TLS connections. You use the 'ssl' module, because that's convenient. You need to let your users configure your SSL/TLS connections, and there really isn't any generic abstract way to do that -- SSL/TLS configuration is pretty complicated -- so you let your users set up an ssl.SSLContext and pass it into your API.

Later, you hit a limit in the ssl module and want to switch to PyOpenSSL, or perhaps eventually PEP 543. No problem: just switch what you're doing internally, and use some shim code to take the ssl.SSLContext objects that your users are passing in, and convert that to whatever your new library wants.

Except... ssl.SSLContext objects are almost entirely opaque. You can't read off the ciphers, or the ALPN protocols, or the servername_callback... so you're sunk. Once you expose ssl.SSLContext in your public API, you're stuck using the ssl module forever.

It would be nice if ssl.SSLContext provided getters that let you read off all the different configuration it holds.
msg308535 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2017-12-18 09:49
I'm considering to add CAPI capsule to the _ssl module. It would allow third parties to get hold of the internal SSL* and SSL_CTX* pointers.
msg308536 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2017-12-18 09:59
Let's see what's missing:

* alpn_protocols -- OpenSSL doesn't have SSL_CTX_get_alpn_protos(), so we'd have to keep the list around ourselves.
* npn_protocols -- deprecated, I'd rather add a getter
* servername_callback -- simply expose the PyObject* from our struct
* ecdh_curve -- OpenSSL has no getter
* ciphers is covered by https://docs.python.org/3/library/ssl.html#ssl.SSLContext.get_ciphers It doens't return the cipher string but the actual list of enabled ciphers with some extra metadata.
msg308541 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2017-12-18 10:30
I opened an issue about missing getters for ALPN protos in OpenSSL 1.1: https://github.com/openssl/openssl/issues/4952
msg308547 - (view) Author: Nathaniel Smith (njs) * (Python committer) Date: 2017-12-18 12:02
I think we already hold onto the ALPN list internally.

A possibly stickier issue is retrieving certificates, keys, trust db configuration.
msg308548 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2017-12-18 12:19
For certs and keys I have some plans. You might not be able to get hold of the actual private key bits, but it is always possible to get the public bits and key information.

The trust store information is pretty much opaque and often loaded by demand. https://docs.python.org/3/library/ssl.html#ssl.SSLContext.get_ca_certs and https://docs.python.org/3/library/ssl.html#ssl.get_default_verify_paths is pretty much everything I know how to retrieve. If find more stuff, I'm more than happy to expose it.
msg308594 - (view) Author: Nathaniel Smith (njs) * (Python committer) Date: 2017-12-18 23:38
Yeah, I'm not entirely sure whether fixing this is actually doable or worthwhile, but figured I should at least make an issue to discuss :-).

The problem is, in the motivating use case of wanting to be able to reliably convert an SSLContext into some other representation, we really need to be able to get 100% of the configuration out. I think the trust configuration can probably be handled in principle by remembering the arguments to any calls to load_verify_locations, so they can be replayed later. But... that won't work for private keys, because if they're password-protected then replaying a call to load_cert_chain will end up prompting for the password twice. So maybe we really would need a way to pull out the actual private key bits. And if we can't do that, then maybe it's not worth stressing about the other stuff either...
msg312890 - (view) Author: Christian Heimes (christian.heimes) * (Python committer) Date: 2018-02-26 08:33
Let's see how much we can fix in 3.8. Maybe I'll find enough free time to implement PEP 543 for Python 3.8.
History
Date User Action Args
2022-04-11 14:58:55adminsetgithub: 76540
2018-02-26 08:33:36christian.heimessetversions: + Python 3.8
messages: + msg312890

assignee: christian.heimes ->
type: enhancement
stage: needs patch
2017-12-18 23:38:34njssetmessages: + msg308594
2017-12-18 12:19:54christian.heimessetmessages: + msg308548
2017-12-18 12:02:13njssetmessages: + msg308547
2017-12-18 10:30:54christian.heimessetmessages: + msg308541
2017-12-18 09:59:37christian.heimessetmessages: + msg308536
2017-12-18 09:49:57christian.heimessetmessages: + msg308535
2017-12-18 09:41:45njscreate