I am currently trying to harden communication over a limited physical communication channel on an embedded system.
The Scenario
I think the system is rather typical for small embedded applications:
The embedded systems involved are small microcontrollers without any OS, which can be assumed to be in a secure physical environment. The connection channel is physically accessible to aggressors, they can interfere with messages as desired.
Different communication channels are possible: e.g. RS485 or RS232. There is a crude protocol which handles stuff like addressing and crude integrity (e.g. CRC16 for bitflips) on which we can build. Think of it as being a slow TCP.
Each communication partner knows a root certificate which can act as a CA and has an own unique certificate(+key) signed by it. Certificates are self signed, elliptic curve prime256v1
The mbedTLS library is available for these systems (with DH, AES, ..).
Most of the time there is no internet available.
The systems can keep time and can create sufficient random numbers
I want to reach privacy, authenticity and integrity.
How it might be solved
A rule in cryptographic protocols is to never implement them on your own. Unfortunately I did not find anything that matches this use case.
I also browsed through existing questions, but nothing provided the full solution i was searching for.
Finally in this answer implementing an own protocol is given as the last option.
This is why I came up with the solution described below - but I am not entirely sure about it. I oriented on this answer on how to authenticate a Diffie-Hellmann Key Exchange, this answer on how to check integrity and this thread giving me some ideas on how to implement such a protocol.
Protocol to secure communication
First thing to do is to randomly generate a symmetric key K. First thing sent is a handshake message. It has the following fields:
Field | Description |
---|---|
DH | The Diffie-Hellmann key exchange msg gK |
Cert | The certificate(-chain) of the sending device |
MsgIdNonce | A random 64-bit value |
Signature | A signature of the complete message using the private key of Cert |
Both devices send (and receive) such a message.
When a message is received the following is done:
- Check if cert is signed by the expected CA (has to be in chain)
- Check if msg is properly signed with cert and its key
When these checks succeed the sent and received DH gK messages are used to calculate a symmetric key.
From this point on, applications can send messages encrypted with AES-CBC. As messages could be lost relatively often, IV is always in the message.
This is the message format:
Field | Description | Encrypted |
---|---|---|
IV | Initialy Random IV for AES | No |
MsgIdNonce | Handshake/Last MsgIdNonce + 1 or + 2 | Yes |
Application Data | The data/commands to protect | Yes |
CMAC truncated to 64 Bit | MAC for checking integrity | Yes |
For a message to be accepted it must
- Have the expected MsgIdNonce (1 or 2 above last received one) - preventing replay attacks, allowing to lose 1 message
- Have a valid CMAC - preventing attacks on integrity
- Be received max. T seconds after the last message - preventing delay attacks
If anything is not as expected, Handshake is sent again, then message is sent again with newly exchanged parameters.
Questions
Am I on the right path or should I try something completely different?
Does this provide my security goals or do I miss any obvious vulnerabilities here?
Can this work?
I hope you can help me and other embedded engineers facing similar problems!
Seems like i was trying to build a AEAD mode myself! - I would change that to GCM.
The channel is bidirectional, and I would use the keys for both directions. MsgIdNonce is valid only for 1 Direction.
– mile4712 Jan 05 '21 at 08:01For rekeying I would send a Handshake whenever I received one - and lose messages with the old key.
Injecting an old handshake message would result in broken communication (MsgIdNonce would not fit for proper messages), which would result in a new Handshake.
You are right, this channel cannot reorder messages.
– mile4712 Jan 05 '21 at 08:02I thought that I would just use a random nonce for each direction, so they are not equal. I thought of replacing it with a counter, but I am not quite sure on how to do that without introducing different roles for the communication partners - at the moment I do not need any roles.
I don't think that both messages sent simoultaneosly are a problem if the implementation sychronizes outgoing and incoming handshakes. So from a conceptional point of view it should work.
– mile4712 Jan 11 '21 at 15:28I will look into RFC7250 in practice, at first sight it seems like it really could relieve the slow transport channel when doing the handshake!
– mile4712 Jan 14 '21 at 14:16