PolarSSL is now part of ARM Official announcement and rebranded as mbed TLS.

Dynamic tls buffer allocation patches at Github


Feb 10, 2018 23:00
Andy Green

Hi -

Thanks for creating and maintaining mbedTLS as FOSS. It fills a very important niche.

At the moment, mbedTLS allocates 32KiB for buffers per connection by default, 16KiB each for rx and tx buffers. On small targets like Cortex M or ESP32, this can represent 10% or more of the total SoC memory, ignoring what other stacks on the device may already have allocated.

The 16KiB max fragment size is mandated by RFC5246, but the potential for memory wastage at the client was recognized by RFC6066, which introduced a maximum fragment size negotiation during the hello phase, where the client (only) can inform the server it will use a smaller max fragment size and the server Is invited to follow. The server cannot inform the client of a similar restriction it wants to impose and so must be able to handle a 16KiB rx fragment.

MbedTLS itself recognized this is a problem at the low end, and introduced a hack MBEDTLS_SSL_MAX_CONTENT_LEN to control the default buffer allocation sizes. However because this is simply a unilateral decision not made explicit in the protocol, unlike the client's ability to make explicit a smaller fragment size to its peer via RFC6066, if a peer unaware of the restriction sends a larger fragment then the TLS connection is aborted immediately. MbedTLS comments MBEDTLS_SSL_MAX_CONTENT_LEN saying it's only useful if you controlled (restricted fragment size) on both ends of the connection, but in many cases interoperability is required or operation with arbitrary browsers or clients using tls is mandatory.

Further MBEDTLS_SSL_MAX_CONTENT_LEN is a build-time constant that restricts all connections made using the library the same, even though different connections for different reasons have different requirements. For example a library built with any restriction on MBEDTLS_SSL_MAX_CONTENT_LEN aimed at one connection where the traffic is known to be sporadic and small, means the library simply can no longer accept browser file upload, which for performance uses 16KiB fragments. So the situation for using mbedTLS on constrained servers particularly is quite uncomfortable.

I have provided a PR https://github.com/ARMmbed/mbedtls/pull/1208 a few weeks ago that provides a patch series introducing dynamically-sized rx and tx buffers. For small packets, the sizes arrived at by passing certs and connection establishment remain sufficient for the whole lifetime of the connection, in my tests on ESP32 that's around 3-4KiB. If larger fragments are sent or received, the buffers realloc accordingly transparently, so there is no restriction on the peer having to follow build-time global pick-a-number restrictions in the library.

These patches impact struct mbedtls_ssl_context which in mbedTLS until now is a public abi. Having what should be an opaque internal struct made visible to consumers and so wanting to be treated as immutable exerts a distorting effect on evolution of the struct itself and code around it, I doubt this is the only case peole have been stubbing toes on it. OpenSSL had the same problem much worse, over the last years they are slowly making opaque all their public abi pieces in favour of accessors; structs definitions that could migrate to internal headers are then open to as much rework and improvement as necessary. So this is a related issue.

The patches are currently in use on top of mbedtls + libwebsockets on ESP32 and memory use is drastically reduced for the test server, which makes several websocket + tls connections back to the server. The last push passes all the mbedTLS selftests that the unpatched tree did.

Since Github does not seem to be an effective path to getting code into mbedTLS, sbutcher suggested starting the discussion here with hanno. Every comment so far has acknowledged dynamic buffers are a desirable addition for mbedTLS, but I'd like to discuss how to go from my working patches to something that is consonant with the maintainer plan and situation for related things like struct mbedtls_ssl_context and MBEDTLS_SSL_MAX_CONTENT_LEN in the project and actually has a way to get committed. If no way, that's also good to know.

-Andy

 
Feb 18, 2018 21:51
Andy Green

At the moment, mbedTLS allocates 32KiB for buffers per connection by default, 16KiB each for rx and tx buffers. On small targets like Cortex M or ESP32, this can represent 10% or more of the total SoC memory, ignoring what other stacks on the device may already have allocated.

Ping!

 
Feb 21, 2018 13:12
Hanno Becker

Hi Andy,

Thank you for your suggestions! As mentioned in the mail I sent to you, we are reworking our messaging architecture, and allowing dynamic allocation of the SSL buffers is indeed one of our considerations.

Given that the intended changes are both very large in scope and not yet in a stable state, though, I think we cannot incorporate concrete code changes based on the old architecture at the moment, while general comments on the use of dynamic buffers and/or on the prospective reworked messaging layer are definitely useful and appreciated.

Thank you for your patience and understanding!

Kind regards,

Hanno