Mbed-TLS / mbedtls

An open source, portable, easy to use, readable and flexible TLS library, and reference implementation of the PSA Cryptography API. Releases are on a varying cadence, typically around 3 - 6 months between releases.
https://www.trustedfirmware.org/projects/mbed-tls/
Other
5.48k stars 2.6k forks source link

Unify error codes #8501

Open gilles-peskine-arm opened 11 months ago

gilles-peskine-arm commented 11 months ago

PolarSSL was designed with each module having its own error codes. So we have, for example, many different MBEDTLS_ERR_xxx_ALLOC_FAILED errors, which tells you which module had a failed allocation. This doesn't actually help in debugging, and makes error handling harder. It also increases the code size because some modules convert errors from lower-level modules into their own errors.

Error codes also have structure: an error code can have a low-level error, a high-level error or a combination of the two. Modules designated as low-level (e.g. individual symmetric algorithms, bignum) raise low-level errors. Modules designates as high-level (e.g. cipher, RSA, X.509, TLS) raise high-level errors possibly combined with a low-level error. This tends to increase the code size and doesn't really help with debugging. (It might be somewhat useful with debugging if an error code contained a detailed trace, but you'd need far more than two levels for that.) Combinations of error codes should be done with MBEDTLS_ERROR_ADD, but it's likely that there are a few places that use a plain +.

PSA has its own set of error codes, which is shared by all PSA APIs.

Minimum goals for this issue:

In 4.0, we may still define legacy aliases to facilitate the transition, e.g.

#define MBEDTLS_ERR_RSA_ALLOC_FAILED PSA_ERROR_INSUFFICIENT_MEMORY

Note that even with these aliases, this is an API break since compilers will no longer accept code like the following (“duplicate case value”):

switch (ret) {
    case MBEDTLS_ERR_RSA_ALLOC_FAILED:
    case MBEDTLS_ERR_ECP_ALLOC_FAILED:
        printf("out of memory");
}

Optional parts:

mpg commented 11 months ago

PolarSSL was designed with each module having its own error codes. So we have, for example, many different MBEDTLS_ERR_xxx_ALLOC_FAILED errors, which tells you which module had a failed allocation. This doesn't actually help in debugging, and makes error handling harder.

I think (but that's just an educated guess) that the intent was not so much helping with debugging as making each module self-contained. For a long time it was a goal that people could take just aes.c + aes.h and no other file an things would work. We've decided some time ago this was no longer something we wanted to support (in large part because it tends to result in code duplication, often with a negative impact on code size), so clearly that's no longer an obstacle to sharing/unifying error codes across modules.

gilles-peskine-arm commented 11 months ago

For a long time it was a goal that people could take just aes.c + aes.h and no other file an things would work

We discussed that as a goal around 2017. Code size didn't feature much in those discussions. Already by that time, it was not the largely case anymore (not even in 1.3): this had been untested for a long time and people had kept including more headers when they felt like it.

Of course it completely went out of the window when we added platform_util.c, later constant_time.c etc.

mpg commented 11 months ago

We discussed that as a goal around 2017.

It was an explicit goal back in the PolarSSL days. (I can remember discussions with Paul where I wanted to introduce shared things and was told "no" for this reason.) I agree that already in 2017 we were largely no longer meeting that goal when we finally made the explicit decision to drop it. All I'm saying is at the time it was still a goal, it probably influenced the decision that each low-level module had its own set of error codes. Fortunately this is no longer an obstacle.