The MbedTLS generally allows you to pass in an RNG callback for each function that requires it. This is even explicitly called out in the 3.x migration guide:
The RNG parameter is now mandatory for all functions that accept one
https://github.com/Mbed-TLS/mbedtls/blob/a7d454cec2/docs/3.0-migration-guide...
However, TLS 1.3 support requires MBEDTLS_PSA_CRYPTO_C
https://github.com/Mbed-TLS/mbedtls/blob/a7d454cec2/include/mbedtls/check_co...
And MBEDTLS_PSA_CRYPTO_C requires MBEDTLS_ENTROPY_C or MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG
https://github.com/Mbed-TLS/mbedtls/blob/a7d454cec2/include/mbedtls/check_co...
This seems to go against the general rule that MbedTLS doesn't require any global state. Was this done intentionally?
Hi Jethro,
Yes, Mbed TLS is moving from being fully stateless to having two pieces of state: a key store and a RNG. This transition is in progress: basically, it concerns code that's enabled by MBEDTLS_PSA_CRYPTO_C or MBEDTLS_USE_PSA_CRYPTO, and in the next major release of Mbed TLS these will be always on.
Passing the RNG argument to certain functions became mandatory in 3.0 because in those functions, blinding is no longer optional at runtime. This is in low-level cryptography interfaces and is unrelated to the evolution towards PSA as the high-level cryptography interface.
For the key store, there is state because it's a level of abstraction that allows the application code to work identically whether a key is available in clear text or stored in a crypto service/partition/chip.
The reason for the RNG being a global state is that in most scenarios, the RNG is a platform choice and the application code doesn't care. The platform integrator knows what entropy sources are available, which PRNG algorithm to choose for speed or code size, whether to use an external cryptoprocessor instead of doing the RNG calculations in software (MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG), whether to have a single RNG instance or one per thread (not implemented yet), etc.
Having an RNG always available also helps with the library evolution. For example, in the past, we ran intro trouble when we wanted to add blinding to a function, to mitigate a side channel, but the function didn't take an RNG argument. In most cases the use of the RNG is internal and it's enough to have one available even if it isn't the one that gets used where it affects the result (e.g. generating nonces), but there can be cases where we would want an RNG to affect the result (e.g. if code that supports only deterministic signature methods is extended to support randomized signatures).
Having this global RNG means that a vast majority of applications don't need to care about the RNG anymore. There is a small number of use cases where one might want to perform a protocol reproducibly. In principle, we could support an optional RNG argument in places like the TLS interface. But then that would require passing that RNG down through the API, all the way to low-level crypto functions, and that is not even possible in all cases — for example if you need to perform an ECDSA signature wirth a key in a secure element that doesn't support deterministic ECDSA. So far we are not planning to support this, because it's a lot of work for a very narrow use case.
So what you're now seeing in the TLS 1.3 interface is the future of TLS in Mbed TLS. I expect that mbedtls_ssl_conf_rng will be gone in Mbed TLS 4.0, even for TLS 1.2.
Best regards,
I've filed https://github.com/Mbed-TLS/mbedtls/issues/7685 for this issue.
-- Jethro Beekman | Fortanix
On 2023-05-21 11:20, Gilles Peskine via mbed-tls wrote:
Hi Jethro,
Yes, Mbed TLS is moving from being fully stateless to having two pieces of state: a key store and a RNG. This transition is in progress: basically, it concerns code that's enabled by MBEDTLS_PSA_CRYPTO_C or MBEDTLS_USE_PSA_CRYPTO, and in the next major release of Mbed TLS these will be always on.
Passing the RNG argument to certain functions became mandatory in 3.0 because in those functions, blinding is no longer optional at runtime. This is in low-level cryptography interfaces and is unrelated to the evolution towards PSA as the high-level cryptography interface.
For the key store, there is state because it's a level of abstraction that allows the application code to work identically whether a key is available in clear text or stored in a crypto service/partition/chip.
The reason for the RNG being a global state is that in most scenarios, the RNG is a platform choice and the application code doesn't care. The platform integrator knows what entropy sources are available, which PRNG algorithm to choose for speed or code size, whether to use an external cryptoprocessor instead of doing the RNG calculations in software (MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG), whether to have a single RNG instance or one per thread (not implemented yet), etc.
Having an RNG always available also helps with the library evolution. For example, in the past, we ran intro trouble when we wanted to add blinding to a function, to mitigate a side channel, but the function didn't take an RNG argument. In most cases the use of the RNG is internal and it's enough to have one available even if it isn't the one that gets used where it affects the result (e.g. generating nonces), but there can be cases where we would want an RNG to affect the result (e.g. if code that supports only deterministic signature methods is extended to support randomized signatures).
Having this global RNG means that a vast majority of applications don't need to care about the RNG anymore. There is a small number of use cases where one might want to perform a protocol reproducibly. In principle, we could support an optional RNG argument in places like the TLS interface. But then that would require passing that RNG down through the API, all the way to low-level crypto functions, and that is not even possible in all cases — for example if you need to perform an ECDSA signature wirth a key in a secure element that doesn't support deterministic ECDSA. So far we are not planning to support this, because it's a lot of work for a very narrow use case.
So what you're now seeing in the TLS 1.3 interface is the future of TLS in Mbed TLS. I expect that mbedtls_ssl_conf_rng will be gone in Mbed TLS 4.0, even for TLS 1.2.
Best regards,
mbed-tls@lists.trustedfirmware.org