Skip to content
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

bpo-37952: SSL: add support for export_keying_material #25255

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

wingel
Copy link

@wingel wingel commented Apr 7, 2021

Add support for the RFC5705 SSL_export_keying_material function to the Python SSL module.

OpenSSL has a function to "SSL_export_keying_material" as described in RFC5705. This functionality is needed to be able to support a bunch of other protocols such as "Network Time Security for the Network Time Protocol" which has now become a proper RFC as RFC8915. There are half a dozen other RFCs which also use this functionality.

This functionality is used in my implementation of the NTS procotol which can also be found on github:

https://github.com/Netnod/nts-poc-python

It would be very nice if mainline Python could support for t his function in the future so that I don't have to maintain a patched version of Python for this.

https://bugs.python.org/issue37952

Copy link
Member

@tiran tiran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please include a blurb, tests, and more documentation. Documentation should explain what the function does, the meaning of each argument with examples and explain at which point of the handshake the function is available.

IMHO it would be helpfup to include an enum with most common export labels for standard TLS.

Modules/_ssl.c Outdated
Comment on lines 212 to 218
/* export_keying_material is present from 1.0.1 */
#if OPENSSL_VERSION_NUMBER >= 0x10001000L
# define HAVE_EXPORT_KEYING_MATERIAL 1
#else
# define HAVE_EXPORT_KEYING_MATERIAL 0
#endif

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Python 3.10 will require OpenSSL >= 1.1.1

Modules/_ssl.c Outdated
Comment on lines 2872 to 2876
if (SSL_export_keying_material(self->ssl,
key, key_len,
label->buf, label->len,
context->buf, context->len,
context->buf != NULL) != 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please follow the error checking style of the module:

Suggested change
if (SSL_export_keying_material(self->ssl,
key, key_len,
label->buf, label->len,
context->buf, context->len,
context->buf != NULL) != 1) {
if (!SSL_export_keying_material(self->ssl,
key, key_len,
label->buf, label->len,
context->buf, context->len,
context->buf != NULL)) {

Modules/_ssl.c Outdated
Comment on lines 2877 to 2878
Py_DECREF(out);
out = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Py_DECREF(out);
out = NULL;
Py_CLEAR(out);

Modules/_ssl.c Outdated
Comment on lines 6425 to 6000
#if HAVE_EXPORT_KEYING_MATERIAL
addbool(m, "HAS_EXPORT_KEYING_MATERIAL", 1);
#else
addbool(m, "HAS_EXPORT_KEYING_MATERIAL", 0);
#endif

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, the feature is always present in OpenSSL 1.1.1

Suggested change
#if HAVE_EXPORT_KEYING_MATERIAL
addbool(m, "HAS_EXPORT_KEYING_MATERIAL", 1);
#else
addbool(m, "HAS_EXPORT_KEYING_MATERIAL", 0);
#endif

Lib/ssl.py Outdated
@@ -1295,6 +1295,14 @@ def verify_client_post_handshake(self):
else:
raise ValueError("No SSL wrapper around " + str(self))

def export_keying_material(self, label, key_len, context = None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def export_keying_material(self, label, key_len, context = None):
def export_keying_material(self, label, key_len, context=None):

Modules/_ssl.c Outdated
Comment on lines 2861 to 2772
if (key_len < 1) {
PyErr_SetString(PyExc_ValueError, "key_len must be positive");
return NULL;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key_len should probably be limited, too.

@@ -1293,6 +1293,12 @@ SSL sockets also have the following additional methods and attributes:

.. versionadded:: 3.3

.. method:: SSLSocket.export_keying_material(label, key_len, context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.. method:: SSLSocket.export_keying_material(label, key_len, context)
.. method:: SSLSocket.export_keying_material(label, key_len, context=None)

Modules/_ssl.c Outdated
Comment on lines 2847 to 2756
label: Py_buffer(accept={buffer, str, NoneType})
key_len: int
context: Py_buffer(accept={buffer, str, NoneType})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you accept buffer, str, and None? Is this suppose to be optional text or bytes? The method should either accept text or bytes.

@bedevere-bot
Copy link

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 I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@tiran
Copy link
Member

tiran commented Apr 7, 2021

Test scenarios:

  • TLS 1.2 server and client side
  • TLS 1.3 server and client side
  • before handshake
  • during handshake
  • after handshake
  • after connection is closed
  • valid and invalid labels
  • with context, with zero length context, without context
  • multiple key lengths

Please also include edge cases for label and context values, e.g. embedded NULL byte, non-ASCII, ...

@wingel wingel force-pushed the export_keying_material-master branch 2 times, most recently from 53c6c8b to 7725b00 Compare April 14, 2021 12:59
@wingel
Copy link
Author

wingel commented Apr 14, 2021

I've updated the patch and I believe that I've addressed all the review comments now.

@wingel wingel requested a review from tiran April 15, 2021 06:51
Copy link
Member

@tiran tiran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix all tests and then follow the instructions of bedevere-bot.

@wingel wingel force-pushed the export_keying_material-master branch 7 times, most recently from 04f2f2a to d20645a Compare April 15, 2021 09:47
@wingel
Copy link
Author

wingel commented Apr 15, 2021

I was told that Python 3.10 will require OpenSSL 1.1.1. Some of these failures are because the tests are run with OpenSSL 1.1.0l which does not seem to support TLSv1.3. Oh well, I've added a check which skips the test if an older version of OpenSSL is used.

And now all tests pass.

@wingel wingel requested a review from tiran April 15, 2021 10:14
Copy link
Member

@tiran tiran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See https://discuss.python.org/t/openssl-3-0-0-support-3-8-to-3-10/8205. I'll drop 1.1.0 and 1.0.2 support next week or the week after.

You need to split the tests and protect each protocol test with @requires_tls_version decorator for each used TLS version.

And please read and follow the instructions of bedevere-bot. The bot will trigger workflow changes and notify me when everything is ok.

@wingel wingel force-pushed the export_keying_material-master branch from d20645a to adb9ead Compare April 15, 2021 13:45
@wingel
Copy link
Author

wingel commented Apr 16, 2021

All checks pass now. It there anything else that's needed?

@wingel wingel force-pushed the export_keying_material-master branch 2 times, most recently from 398cd73 to 60f65cd Compare April 22, 2021 09:19
@wingel wingel requested a review from tiran April 22, 2021 09:40
@wingel
Copy link
Author

wingel commented Apr 22, 2021

Pull request updated to work after bpo-42333 and bpo-43669.

@wingel
Copy link
Author

wingel commented Apr 26, 2021

I have made the requested changes; please review again

@wingel wingel force-pushed the export_keying_material-master branch 4 times, most recently from 4e1865f to c23bd08 Compare June 14, 2021 08:32
@wingel wingel force-pushed the export_keying_material-master branch 2 times, most recently from 97884bb to c1b14f0 Compare August 18, 2021 11:46
@wingel
Copy link
Author

wingel commented Aug 19, 2021

@tiran Can you please take a look at this patch again?

@wingel
Copy link
Author

wingel commented Aug 19, 2021

I have made the requested changes; please review again

@bedevere-bot
Copy link

Thanks for making the requested changes!

@tiran: please review the changes made to this pull request.

@lowinger42
Copy link

@tiran Is there any way to get this pull request accepted?
/AL

Add support for the RFC5705 SSL_export_keying_material function
to the Python SSL module.
@wingel wingel force-pushed the export_keying_material-master branch from c1b14f0 to 51a8a5c Compare January 11, 2022 10:05
@wingel
Copy link
Author

wingel commented Jan 11, 2022

Yet another year, yet another update of my patch.

I have made the requested changes; please review again

@bedevere-bot
Copy link

Thanks for making the requested changes!

@tiran: please review the changes made to this pull request.

@AlexWaygood AlexWaygood added type-feature A feature request or enhancement and removed stale Stale PR or inactive for long period of time. labels Jan 11, 2022
@wingel
Copy link
Author

wingel commented Jan 11, 2022

Have I missed anything? It would be nice to get some kind of feedback.

@tiran tiran removed their request for review January 11, 2022 10:53
@tiran
Copy link
Member

tiran commented Jan 11, 2022

I no longer think that this feature should land in Python core. The ssl module provides a opinionated and limited API. Exporting key material a special feature for a narrow use case. Python core dev has limited resources. I'm basically the only maintainer of the ssl module and I don't want to burden myself with supporting this feature for the next five to ten years.

I would rather move https://bugs.python.org/issue43902 forward so third party developers can use ctypes, cffi, or C code to access and modify raw SSL_CTX* and SSL* pointers.

@eighthave
Copy link

eighthave commented Mar 20, 2022

@tiran thanks for your ongoing maintenance of ssl! Although I would like to see this pull request land, https://bugs.python.org/issue43902 would also work fine for my use case. Exporting keying material is being used more and more in IETF standards, and is pretty widely implemented:

@TheZ3ro
Copy link

TheZ3ro commented Mar 11, 2023

Sad to see that Python still don't have this in its ssl module :(
Basically every language has this and its becoming more and more used.

Is there an alternative way to export keying material?

@Neustradamus
Copy link

@wingel, @tiran: Have you progressed on it since more one year?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet