Repository navigation
extmod/modssl_mbedtls: Implement SSLSession support. - #12780
DvdGiessen wants to merge 5 commits into
Conversation
57c5d78 to
43824ae
Compare
|
Code size report: |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #12780 +/- ##
==========================================
- Coverage 98.58% 98.57% -0.02%
==========================================
Files 182 182
Lines 23322 23375 +53
Branches 5 5
==========================================
+ Hits 22993 23041 +48
- Misses 328 333 +5
Partials 1 1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
43824ae to
53bb552
Compare
53bb552 to
e529117
Compare
|
This is an automated heads-up that we've just merged a Pull Request See #13763 A search suggests this PR might apply the STATIC macro to some C code. If it Although this is an automated message, feel free to @-reply to me directly if |
f014564 to
6c50ae1
Compare
6c50ae1 to
9a48098
Compare
|
Updated on latest master branch, added server-side support for TLS tickets to the Unix port, and added a test that checks (a) that SSLSession works and (b) that session resumption actually results in decreased data usage. I've been using various versions of this patch for almost a year now to resume HTTPS connections without any trouble (though that might just be because I didn't try with many different configurations). Marked as ready for review. EDIT: And re-pushed because I forgot to add the documentation commit. |
caeb380 to
feae3a7
Compare
feae3a7 to
a7c1dc6
Compare
|
Hi Daniël, Do you plan to update the asyncio implementation to use this functionality? If that was done it would be a minor effort to add SSL session support to many micropython web libraries. Currently, we session set up times in the order of 5 seconds on the PICO W, the lack of SSL session reuse is a showstopper for web apps using asyncio's new SSL support. Cheers, Charlie |
|
Hi Daniël, |
|
I didn't look into how to use this with asyncio before. It appears that in CPython there is no interface to use SSLSessions with asyncio. For the core support we'd need to for example add a For that reason I might prefer to split this into a separate follow-up PR, since it doesn't impact the changes proposed here and thus does not need to block considering / reviewing / merging this PR. |
|
@DvdGiessen Hi Daniël, I agree that the change is best handled as a separate PR as it requires changing the asyncio implementation to add session to the wrap_socket call. Cheers, Charlie |
a7c1dc6 to
06c5929
Compare
06c5929 to
30ce6ac
Compare
30ce6ac to
95e5585
Compare
95e5585 to
4f91e1c
Compare
4f91e1c to
2e1b344
Compare
2e1b344 to
16223e9
Compare
16223e9 to
4f8529d
Compare
4f8529d to
3eca373
Compare
3eca373 to
70df1af
Compare
70df1af to
88c4c9c
Compare
88c4c9c to
d43cbc0
Compare
d43cbc0 to
1aeca3e
Compare
|
Wondering what's the plan on this one, it's an important addition |
|
I'm still using it, which is why I occasionally update it to resolve merge conflicts, and the MR is ready for review. Note #17074 was recently merged, which implements the PSK support. I haven't had time to look at it and don't know exactly what's possible with mbedTLS, but I think that supporting TLS 1.3 session resumption with a PSK would be nice to have, maybe even with the same interface so it works regardless of whether you're connecting to 1.2 or 1.3 peers. |
|
Thanks for keeping this PR active. It looks good and I've put it on the milestone for the next release. |
dpgeorge
left a comment
There was a problem hiding this comment.
Thanks for the contribution here. I've now done an initial review and it's looking pretty good.
I made some comments inline. But i also had a bigger-picture thought about how the feature is implemented.
Considering that we don't need to be compatible with CPython (this is the tls module which is MicroPython-specific), it's not actually necessary to have the SSLSession object at all. It can just be a bytes object and always serialized. So, doing ssl_sock.session will return the serialized session as a bytes, and you pass that bytes back when you want to resume.
Benefits of that approach:
- simpler, smaller API surface
- less code, probably smaller firmware
- there's no separate serialize/unserialize step
- resource management is easier (wrt to calling
mbedtls_ssl_session_free())
Drawbacks:
- probably takes longer to serialize/unserialize every time you want to resume a session (although, if you anyway are serializing between connections there's no difference)
- not possible in the future to add extra methods/attributes to the SSLSession (because it's just a
bytes)
What do you think?
| } | ||
|
|
||
| static const mp_rom_map_elem_t ssl_session_locals_dict_table[] = { | ||
| { MP_ROM_QSTR(MP_QSTR_serialize), MP_ROM_PTR(&ssl_session_serialize_obj) }, |
There was a problem hiding this comment.
Since it's possible to use bytes(session) to serialize it, I don't think this method is needed. It just means there are two ways to do the same thing, and the Zen of Python says there should ideally be only one obvious way.
In your use of this feature, do you find one of these ways more convenient than the other?
| } | ||
| } else if (dest[1] != MP_OBJ_NULL) { | ||
| // Store attribute. | ||
| if (attr == MP_QSTR_session) { |
There was a problem hiding this comment.
Is it necessary to be able to store to ssl_socket.session to set the session? Or is it enough to just pass the session through to wrap_socket()? Or are there situations where both of these ways of setting the session are needed?
Note that we do not need to match CPython here, because this is now the tls module. So we are free to design the API however we like. That said, if it's easy and efficient to match CPython, then that's definitely preferable.
| mp_buffer_info_t bufinfo; | ||
| mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_READ); | ||
|
|
||
| mp_obj_ssl_session_t *self = m_new_obj(mp_obj_ssl_session_t); |
There was a problem hiding this comment.
Does this type need a finalizer to call mbedtls_ssl_session_free()? It looks like mbedtls does some internal allocations using mbedtls_calloc() when populating a session. And they will need to be freed manually.
| } | ||
|
|
||
| if (ssl_session != mp_const_none) { | ||
| mp_obj_ssl_session_t *session = MP_OBJ_TO_PTR(ssl_session); |
There was a problem hiding this comment.
This probably needs a type check to make sure the session really is a SSLSession.
| // Load attribute. | ||
| if (attr == MP_QSTR_session) { | ||
| mp_obj_ssl_session_t *o = m_new_obj(mp_obj_ssl_session_t); | ||
| o->base.type = &ssl_session_type; |
There was a problem hiding this comment.
Can use the helper mp_obj_malloc(mp_obj_ssl_session_t, &ssl_session_type) here.
| os.stat(keyfile) | ||
| except OSError: | ||
| print("SKIP") | ||
| raise SystemExit |
There was a problem hiding this comment.
This check can go. All the multi-net tests assume that the cert files are available.
|
@Gadgetoid I think this feature might be of interest to you. |
|
@DvdGiessen any comments on the above review? This is a good feature to have, just need to consider the overall API approach. |
|
Sorry, this slipped of my radar. Thanks for for the feedback! I agree it would indeed make the code simpler, I'll see about making the changes when I find some time. |
Signed-off-by: Daniël van de Giessen <[email protected]>
Signed-off-by: Daniël van de Giessen <[email protected]>
Signed-off-by: Daniël van de Giessen <[email protected]>
Signed-off-by: Daniël van de Giessen <[email protected]>
Signed-off-by: Daniël van de Giessen <[email protected]>
1aeca3e to
d221ba5
Compare
Summary
This implements support for the
SSLSessionclass, introduced in CPython in 3.6 (see #2415). It allows saving session data from an active TLS client-side connection and then creating a new connection re-using this session data. Benefits include a faster handshake and reduced data usage for short connections.Implementation details
This PR adds the
SSLSessionclass, thesession=parameter for theSSLContext.wrap_socket()method, and thesessionattribute for anSSLSocketobject.Additionally, I've added a non-standard part: The
SSLSession.serialize()function that converts the session to a bytes object (also available via the buffer protocol, so perhaps exposing this function is redundant); so that it can be stored by the user, and a constructor for the SSLSession object that accepts a bytes-like object to reconstruct the session object (CPython doesn't allow direct construction). This allows storing the session somewhere and use it after a deep sleep or reboot.The second commit adds server-side support for TLS tickets in the Unix port, so that we can meaningfully test the session resumption in tests. The third commit adds a test which tests session resumption using the
SSLSessionobject, checking that the resumption worked by checking that a resuming consumes less data.micropython/micropython-lib#829 is a companion MR that implements support in the
sslmodule wrapper. It is required for the tests to pass.Usage example
A small example test, using a wrapper class around the TCP socket so we can count how many bytes of data we're sending/receiving:
Testing
I've deployed this in production and been running it for a number of years on a large number of devices.