8000 extmod/modussl: improve exception error messages by tve · Pull Request #5819 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

extmod/modussl: improve exception error messages #5819

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

Closed
wants to merge 10 commits into from

Conversation

tve
Copy link
Contributor
@tve tve commented Mar 27, 2020

This PR is a proposal for adding human readable error messages when mbedtls or axtls raise an error. Currently often just an EIO error is raised so the user is lost and can't tell whether it's a cert error, buffer overrun, connecting to a non-ssl port, etc.

Mbedtls: fortunately mbedtls provides a strerror function to return proper error messages. Sadly it's pretty huge: about 16KB on the ESP32. We could also just print the numeric error code, but the problem is that often there's no convenient place to look them up due to the way mbedtls combines high-level and low-level error codes.

This PR modifies the mbedtls error raising to be similar to the check_esp_err stuff, i.e., it produces an OSError(-err_num, "error string") where the error string comes from mbedtls' strerror, and if there is an out of memory condition it just produces OSError(-err_num).
Producing the error string is conditioned on them being included in the mbedtls build, i.e., if they're there anyway then the OSErrors will have them, else they won't.

The esp32 build has the mdbedtls error strings, it's in the mbedtls config which is inherited from esp-idf. The pybd doesn't. IMHO by the time one include 8000 s all the mbedtls code adding the 16kB of strings is a drop in the bucket (even though it's a sucky implementation on their end)...

Just to mention: we could replace the insane sequence of if statements in mbedtls' strerror by a table. That seems like a lot of work.

This PR also fixes the axtls lib to behave the same way. For this I created a small error table. I'm not so familiar with axtls but that seemed like the best option. I tested that on unix but can't test the OOM condition there. I'm trying to get a build for the esp8266 going but so far crosstool-ng isn't building for me (I really don't want the docker mess on my machine...).

@tve tve changed the title extmod/modussl_mbedtls: radd message to exception on handshake error extmod/modussl_mbedtls: add message to exception on handshake error Mar 27, 2020
@JLFra
Copy link
JLFra commented Mar 28, 2020

Hello,
I have a ESP32 Wroom 32D.
I try to install picoweb.
I use the last firmware
http://micropython.org/resources/firmware/esp32-idf4-20200328-v1.12-310-g9418611c8.bin

here is the issue:

Installing to: /lib/
Warning: micropython.org SSL certificate is not validated
Installing picoweb 1.8.1 from https://files.pythonhosted.org/packages/ba/e4/68983f6150f7fbd98b6b937bf7f76aeb4eb9ba4abb7c93dc05b2ccdbd25c/picoweb-1.8.1.tar.gz
mbedtls_ssl_handshake error: -71
Error installing 'pycopy-uasyncio': [Errno 5] EIO, packages may be partially installed
Traceback (most recent call last):
File "", line 41, in
File "/lib/picoweb/init.py", line 12, in
ImportError: no module named 'pkg_resources'

Thanks to help me.
regards.
JL

@tve
Copy link
Contributor Author
tve commented Mar 28, 2020

Hello,
I have a ESP32 Wroom 32D.
I try to install picoweb.
I use the last firmware
http://micropython.org/resources/firmware/esp32-idf4-20200328-v1.12-310-g9418611c8.bin

here is the issue:

Installing to: /lib/
Warning: micropython.org SSL certificate is not validated
Installing picoweb 1.8.1 from https://files.pythonhosted.org/packages/ba/e4/68983f6150f7fbd98b6b937bf7f76aeb4eb9ba4abb7c93dc05b2ccdbd25c/picoweb-1.8.1.tar.gz
mbedtls_ssl_handshake error: -71
Error installing 'pycopy-uasyncio': [Errno 5] EIO, packages may be partially installed
Traceback (most recent call last):
File "", line 41, in
File "/lib/picoweb/init.py", line 12, in
ImportError: no module named 'pkg_resources'

Thanks to help me.
regards.
JL

The good news is that I can repro, the bad news is that I don't like the result :-)

MicroPython v1.12-317-g995f79a88 on 2020-03-27; ESP32 module with ESP32
Type "help()" for more information.
>>> import upip
>>> upip.install('picoweb')
Installing to: /lib/
mbedtls_ssl_handshake error: -113/-0x71
Error installing 'picoweb': mbedtls -0x71: UNKNOWN ERROR CODE (0071), packages may be partially installed
>>>

(As I mentioned in the forum thread, 0x71 is 113 which is EHOSTUNREACH)

@JLFra
Copy link
JLFra commented Mar 28, 2020 via email

@JLFra
Copy link
JLFra commented Mar 28, 2020 via email

@tve
Copy link
Contributor Author
tve commented Mar 28, 2020

mbedtls_ssl_handshake error: -113/-0x71
Error installing 'picoweb': mbedtls -0x71: UNKNOWN ERROR CODE (0071), packages may be partially installed


(As I mentioned in the forum thread, 0x71 is 113 which is EHOSTUNREACH)

It turns out that error 113 is not EHOSTUNREACH but ECONNABORTED. This is another case of posix errno.h vs newlib errno.h, see #5830

@tve
Copy link
Contributor Author 8000
tve commented Mar 28, 2020

After several hours of wild goose chase....:

  • the connection is aborted because the network interface is being shut down
  • the interface is being shut down because the wifi_sta interface is being shut down
  • the wifi_sta interface is being shut down because an event to that effect is being generated out of the espressif binary blobs from ieee80211_sta_new_state

I can reproduce this with >90% probability using test/net_inet/test_tls_sites.py when it connects to api.telegram.org. Very infrequently it all works as it should. I'm kind'a wondering whether what I'm seeing isn't memory corruption somehow somewhere...

@tve
Copy link
Contributor Author
tve commented Mar 29, 2020

More wild goose chase... it turns out the real issue is:

api.telegram.org mbedtls -0x4290: RSA - The public key operation failed : BIGNUM - Memory allocation failed

I suspect that what happens is that memory gets very low and then what fails depends on random stuff. If "all goes well" it's mbedtls that reports a memory error, if things go south then some other random part of esp-idf can't allocate some buffer and then the wifi sta interface is being shut down. Sigh.

@tve
Copy link
Contributor Author
tve commented Mar 29, 2020

I updated the PR to resolve the discrepancy between py/mperrno.h and the errno.h used by lwip. The solution turned out to be relatively simple. Lwip's socket implementation really gets lwip-specific error numbers from its netif layer and has a small table translating those to "posix" error numbers using EXXX constants. What I did is remove the lwip err.c file from the build and replace it with a same file that uses MP_EXXX constants instead. This means that if anything else is still using the EXXX constants they may be off, but at least what comes out of lwip is fixed.

@tve
Copy link
Contributor Author
tve commented Mar 29, 2020

Looks like it doesn't like the test I just fixed-up. I can't tell what fails since it prints no info other than "it failed". When I run it, it works fine:

> env MICROPY_MICROPYTHON=../ports/unix/micropython-coverage ./run-tests extmod/ussl_basic.py
pass  extmod/ussl_basic.py
1 tests performed (7 individual testcases)
1 tests passed

tve added a commit to tve/micropython that referenced this pull request Mar 31, 2020
@tve tve force-pushed the mbedssl-strerror branch 2 times, most recently from f871529 to 2340b8d Compare April 2, 2020 07:12
@tve tve changed the title extmod/modussl_mbedtls: add message to exception on handshake error extmod/modussl: improve exception error messages Apr 2, 2020
@tve tve force-pushed the mbedssl-strerror branch 2 times, most recently from ea84352 to 854756b Compare April 21, 2020 02:00
@tve
Copy link
Contributor Author
tve commented Apr 21, 2020

I rebased on latest master, however, this needs some slight rework after #5850 goes in so it's compatible.

@tve tve force-pushed the mbedssl-strerror branch 2 times, most recently from 43260c6 to fdda2e0 Compare April 24, 2020 18:02
@tve
Copy link
Contributor Author
tve commented Apr 24, 2020

@dpgeorge please review.
So as far as I'm concerned this is ready to merge

This was referenced May 1, 2020
@dpgeorge dpgeorge added the extmod Relates to extmod/ directory in source label May 11, 2020
@dpgeorge
Copy link
Member

Thanks for this.

The main discussion point would be whether adding "user friendly" error messages is in the spirit of MicroPython, trying to be minimal. Giving just the error code (and no stripng) is the most minimal thing to do because then at least you can look up this code to see what it corresponds to.

But even if you can lookup the error code in the source that's not necessarily easy to do (eg which version of the code? what configuration options were enabled? what if I'm out in the field and get a connection error and don't have access to source code to look it up?).

Also, unlike standard errno codes (like EAGAIN), the TLS codes are many and obscure, so you can't really remember what corresponds to what.

And experience has shown that users are often confused about the TLS error messages. Since SSL connections are already hard enough and sometimes unreliable, having obscure error codes without error messages just compounds the problem.

So IMO this PR is a worthy addition. But maybe it'd be good to make it configurable with a compile-time option, eg MICROPY_PY_USSL_ERROR_REPORTING?

// It is set/unset in the MBEDTLS_CONFIG_FILE which is defined in the Makefile.
// "small" negative integer error codes come from underlying stream/sockets, not mbedtls
if (err < 0 && err > -256) {
mp_raise_OSError(-err);
Copy link
Member

Choose a reason for hiding this comment

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

Is this code path tested?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No. I just tried to write a test and failed to come up with something. It will be tested as part of #5825, however. What's missing is that at the current point read/write don't go through the SSL error string stuff. #5825 fixes that and more.

@@ -1,5 +1,4 @@
ssl_handshake_status: -256
wrap_socket: OSError(5,)
wrap_socket: OSError(-256, 'CONN_LOST')
Copy link
Member

Choose a reason for hiding this comment

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

This test obviously only works with axtls, but that's ok for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As written the test can only work with axtls, which is a shame. The problem is that using io.Bytes doesn't work with mbedtls.

@dpgeorge
Copy link
Member

The esp32 build has the mdbedtls error strings, it's in the mbedtls config which is inherited from esp-idf. The pybd doesn't. IMHO by the time one includes all the mbedtls code adding the 16kB of strings is a drop in the bucket (even though it's a sucky implementation on their end)...

Yes, after this patch I'd enable MBEDTLS_ERROR_C for PYBD. It's useful and worth the code size increase.

Just to mention: we could replace the insane sequence of if statements in mbedtls' strerror by a table. That seems like a lot of work.

It might be worth doing this, and also shortening the error messages to be like it's done here for axtls, eg for MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE it'd be OSError(-30592, 'SSL_FATAL_ALERT_MESSAGE'). That's still "user friendly" and could cut the error code in half. (Of course this change is out of scope for this PR.)

@tve
Copy link
Contributor Author
tve commented Jun 3, 2020

Yes, the perl script is not great but I kept it as-is for exactly the reasons you mention and I hope that makes it all easier to maintain. It comes from https://github.com/ARMmbed/mbedtls/tree/development/scripts (I used the version in lib/mbedtls), I' can add a note WRT licensing into the README (it's the mbedtls Apache 2.0 license).

@dpgeorge
Copy link
Member
dpgeorge commented Jun 4, 2020

Instead of committing the original and modified files for generate_errors.pl and error.fmt, how about committing just the diff/patch file for these, and then the do-xxx.sh scripts first generate these modified files using the path before running them? That should be easy to do, means less code checked in here.

@dpgeorge
Copy link
Member
dpgeorge commented Jun 4, 2020

I wasn't sure about where to place files.

I think the new directory extmod/mbedtls_errors/ would have a better home at lib/mbedtls_errors/ so it lives alongside lib/mbedtls/. Then it's considered more of a modification to mbedtls rather than a necessary part of extmod's modussl_mbedtls. It also keeps 3rd party code in lib/.

F438
@tve tve force-pushed the mbedssl-strerror branch from 9f0bc92 to 7e1cdf0 Compare June 20, 2020 17:29
@dpgeorge
Copy link
Member

I see there are changes pushed here. Is it ready for re-review?

@tve
Copy link
Contributor Author
tve commented Jun 23, 2020

Thanks for the reminder! I got stuck re-running tests on my pybd before asking for re-review.

@tve
Copy link
Contributor Author
tve commented Jun 25, 2020

I did finally run the tests and things look OK. The latest changes:

  • integrate the smaller issues flagged in the comments
  • change the file generation to use diffs instead of copies of files
  • move the mdebtls_errors dir to lib
  • added feature to pybd-3 and pybd-6 (I can't test those, only the pybd-2)

@dpgeorge I would appreciate a re-review.

@tve tve force-pushed the mbedssl-strerror branch from a444181 to 6c9622a Compare July 2, 2020 19:48
@tve tve force-pushed the mbedssl-strerror branch from 6c9622a to b56866a Compare July 2, 2020 20:02
@tve
Copy link
Contributor Author
tve commented Jul 2, 2020

@dpgeorge all comments but one addressed

@dpgeorge
Copy link
Member

@tve thanks for updating, it all looks good now.

But, it'll need to be squashed/split into a few commits, like:

  • the initial commit to improve exception error messages for both axtls and mbedtls
  • a commit to add strncpy
  • a commit to add the lib/mbedtls_errors code
  • a commit to wire the new error code up to esp32 and stm32

I'm happy to do this by reworking your existing commits (so your name as will appear as author of them). Just let me know if I should go ahead, or if you want to do it yourself.

@tve
Copy link
Contributor Author
tve commented Jul 20, 2020

Great! I would appreciate if you did the rework 'cause you know what you want so we don't go around the block again...

@dpgeorge
Copy link
Member

Ok, will do.

@dpgeorge
Copy link
Member

Reworked in #6259

@dpgeorge
Copy link
Member

Commits reworked and merged in 9aa2140 through 5264478

Thanks @tve for all the hard work on this! It should make a big improvement for users debugging SSL errors.

@dpgeorge dpgeorge closed this Jul 20, 2020
tannewt pushed a commit to tannewt/circuitpython that referenced this pull request Jan 13, 2022
Add Piunora and Zero. Also, enable full build
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extmod Relates to extmod/ directory in source
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0