mbed tls DTLS v1.2 system with -ECDHE-ECDSA, mutual auth and pre-installed public/private keys, no unnecessary messages or ASN.1/X.509 decoding I am designing an IoT system based on Silicon Labs EFR32 MCUs with hardware accelerated support for SHA-256, AES-128-CBC and ECC (m255) computation. The system will communicate over a proprietary radio communication protocol in an untrusted environment, and both flash and ram footprint and the number of exchanged messages is vital to be kept low.

The DTLS functionality described in https://tools.ietf.org/html/rfc6347 is massively overweight for my application, which has the following features and needs:


micro-controller to micro-controller communication using proprietary radio (not LoRa, Zigbee or similar) in a hostile environment, radio is slow and costly in terms of battery life
non-blocking SW model with callbacks and timer hooks
physical channel: unreliable delivery, active attacker/listener, reordering and replay; similar to UDP.
client/server model with client verification similar to HelloVerifyRequest/ClientHello in DTLS to avoid DOS attacks on the other radio devices
exclusive use of TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 (m255) known at production time
known maximum MTU size for radio channel
pre-installed public/private key-pair in both peers in compact binary form (no ASN.1 or X.509 code), identical to both peers having each other's certificates without negotiation, with eternal validity
no IP, not be reachable online, communication between two micro-controllers that use a proprietary protocol for communication
pause/start the tunnel without it closing when no traffic comes in the paused state. Shouldn't renegotiate when in paused state, but keep using the session keys until either age-limit or data-limit hit. Needs to be possible to wake up by an unencrypted agent
one bi-directional secure, mutually authenticated application-layer traffic tunnel using ECDHE/ECDSA, no port-numbers needed.
client knows unique serial number of server, server knows only it's own serial number
keep-alive signaling; successful payload message transfer should be seen as keep-alive equivalent to reduce message volume
renegotiate session keys when either age-limit or data-limit hit
client knows the unique serial number of the server, needs to do server device discovery among potentially many devices both after and before session establishment. That a device has been seen is not considered secret information


When I look at what already finished functionality mbed DTLS has, it looks like I can't get it to not exchange certificates between peers or negotiate the cipher suite (despite knowing the only valid setting in production). I want to cut out all the unnecessary, already known flights of messages to reduce both setup time and battery consumption.

I want to have two interfaces towards my L1 radio layer where only a rough selection of incoming traffic has been performed: send() and receive(), which should be asynchronous and non-blocking.

The code and RAM size for ASN.1 decoding and parsing is massive for my application, so I want only the 256+256 bits of the public/private key-pair, and the known unique serial number of the peer to be stored instead of doing ASN.1 and X.509 parsing.

Is there any way to obtain the features that I want, or do I need to write this code myself, implementing heartbeat signaling, session establishment/renegotiation, application layer tunnel traffic encryption/authentication/decryption, etc based on mbed tls DTLS primitive functions?

Is there any known example of a similar scenario that I can look at? Any list of good advices to follow in order to avoid creating exploitable weaknesses in my implementation?

Thankful for any helpful input
/Daniel Nilsson
You can write your own protocol instead of using DTLS. But there's no realistic chance that you'll get it right. Designing a secure protocol is hard, and you should definitely use a proven and tested one rather than roll your own.

You can do DTLS with raw public keys, which would avoid X.509 altogether. This saves a number of things: code size, RAM usage (but not a lot, compared to a self-signed certificate), and handshake message size. You still need two round trips to establish a session using raw public keys. This does have security and deployment drawbacks: you have to distribute all the peers' public keys before you can start communicating, and you have to manage repudiation on your own.

If you find an implementation of it, that is. Mbed TLS doesn't support it, although there's an old pull request for it. Reportedly tinydtls can do it.

Do use session caching and resumption whenever possible. Session resumption removes the cost of public-key cryptography and reduces the number of round trips to start the connection from 2 to 1.

TLS 1.3 will let you establish a session with a single round trip, but DTLS 1.3 isn't ready yet.

In the absence of a usable implementation of DTLS with raw public keys, you may be forced to partially roll your own: use DTLS with pre-shared symmetric keys (this is widely supported by (D)TLS implementations), and use a separate protocol to distribute the symmetric keys. But it would be safer to achieve this by using DTLS to effectively distribute the symmetric keys, and session resumption to avoid doing asymmetric cryptography every time.