>> µTLS - DEFINING LIGHTWEIGHT SECURITY FOR IoT (PART 1)
I have been meaning to come back to this for quite some time - enough is
enough.
Since I started this blog, security has been one hell of a topic that I
have covered within the field of Internet of Things (IoT) - such as the
general mass fear complete to actually taking the time to test the
feasibility
of security on micro-controllers. It is time we did something about it;
more than just talking about it - but actually building a protocol and
implementing it. I am proud to introduce µTLS!
µTLS (micro
Transport Layer Security)
is a protocol that aims to provide privacy and data integrity between two
communicating computer applications, with limited CPU power and memory
resources, specifically for use within the Internet of Things (IoT) field.
It is designed to be open and flexible; to suit the demands of the various
micro-controllers that are in use.
The µTLS protocol is implemented over non-encrypted HTTP traffic
and is designed under the pretense that unless anyone listening in on
the conversation speaks the same language - then the contents of the
information exchanged remains private and as such secure. It is no
different than two people talking Mandarin amongst a group of English
who do not understand Mandarin.
COMMUNICATION HANDSHAKE
The handshake phase occurs when the client device establishes communication
with the server with the desire to exchange information; either for the
purpose of uploading sensory data or requesting operational instructions -
the terms of communication must be defined.
A session creation request may look as follows:
POST /index.php
{
"guid": "ffa90e64-f3e2-4697-b98c-e3c13d1b2362",
"security": {
"protocol": "none",
"response": "none",
"protocol_sub": "none"
},
"info": {
"name": "Weather Station",
"company": "RIot International Pty Ltd",
"build": "2016-12-01",
"version": "1.0"
}
}
The request is quite simple, requiring the guid (identifier)
and security keys as a bare minimum - they are used to determine if
the server can trust the client or not. The info key can be
optionally provided; depending on the requirements of the application.
In this case; the security.protocol is set to none
and that the client expects the response to be unencrypted for further
communications as defined in the security.response and
security.protocol_sub keys.
On successful validation; the server responds with information on how
to make subsequent requests to allow the exchange of information with
the client. An example of such a response is:
{
"session": "e91f5584152639c72d5358a05f9cd887584edaf9b6f06",
"security": {
"protocol": "none",
"response": "none"
}
"data": {
"ts": "1481544512"
}
}
A unique session key is provided that the client can use
to avoid having to re-validate itself with the server every time.
The security definition has two components; the protocol to use in the
response and how the client should continue talking to the server.
These are defined in the security.response and
security.protocol keys - in the example these are defined as
none. Optionally, the data key can contain information
that may be of use to the client (such as sending the server timestamp
to sync time locally on the client).
The client can then make subsequent requests:
PUT /index.php
{
"session": "e91f5584152639c72d5358a05f9cd887584edaf9b6f06",
"security": {
"protocol": "none",
"response": "none"
}
"data": {
"buffer": "xxyyzzxxyyzzxxyyzz....xxyyzzxxyyzzxxyyzz"
}
}
The data.buffer will then contain the HEX encoded buffer
that the client wishes to send to the server for processing. Utilizing the
security method defined in security.protocol the server can then
process the information received and can respond to the client appropriately:
{
"session": "e91f5584152639c72d5358a05f9cd887584edaf9b6f06",
"security": {
"protocol": "none",
"response": "none"
},
"data": {
"ts": "1481544610",
"buffer": "xxyyzzxxyyzzxxyyzz....xxyyzzxxyyzzxxyyzz"
}
}
In this example; there is absolutely no security in the communication.
In a production environment; this would not be a sensible setup to use -
as the data would be sent without any protection and the server will not be
capable of validating if the client is who they claim to be. The next step
would be to extend the protocol to define a level of security.
COMMUNICATION SECURITY
Within the initial communication between the client and server - the client
defines the security key - it is vital as it defines how the
client and server should exchange information in addition to allow for
some low-level checking to verify if the client is actually who they say
they are.
The security.protocol key defines the sub-protocol to be used
as part of the validation; and the security.buffer key contains
a HEX encoded buffer of information the server can use to verify the
legitimacy of the client. On failure, the server rejects communication.
The exact nature of how the client and server perform this validation
is completely open - the only requirement is that whatever input data
required to generate the security.buffer based on the sub-protocol
security.protocol must be provided within the request.
As an example; here is a much more secure configuration:
For example, consider the following security definition.
"security": {
"protocol": "rsa-1024",
"response": "rsa-1024",
"protocol_sub": "aes-128",
"buffer": "xxyyzzxxyyzzxxyyzz....xxyyzzxxyyzzxxyyzz"
}
In this case the client has sufficient resources to perform a 1024 bit
private-key RSA encryption operation locally. The client has also indicated
that it can handle 1024 bit RSA of the server and the AES-128 protocol. The
server could now use the guid key to find the corresponding
public-key of the client and then decrypt the data in security.buffer
- if it is a successful request then the result will match a value
that only the client and server is aware of.
On successful validation; the server will respond with:
{
"session": "e91f5584152639c72d5358a05f9cd887584edaf9b6f06",
"security": {
"response": "rsa-1024",
"protocol": "aes-128"
}
"data": {
"ts": "1481544512",
"params": "abcdef",
"buffer": "xxyyzzxxyyzzxxyyzz....xxyyzzxxyyzzxxyyzz"
}
}
Similar to the insecure response; a unique session key is
provided to avoid having to re-validate itself with the server every time,
in addition to the security.response and security.protocol
keys - defining how to handle the response and make further communication.
The client has defined the security protocols it can handle, so the server
can now respond appropriately.
In this example; the client requests to communicate using aes-128.
However; in order to initialize the protocol; it needs to send over a
number of base values - in this case, the buffer to initialize AES-128 with.
rsa-1024 has been requested for the response of the request - the
data will then be encrypted using the private key of the server and placed
in the data.buffer key.
If some parameters are required to give context on how to
process the data.buffer structure once it is decoded from a HEX
string; these parameters will be passed in unencrypted form via the
data.params key - such as syncing indexes between server
and client.
The client now has all the information it needs to process the result -
and extract the information stored in the data.buffer key. It can
as a result use the 1024-bit RSA algorithm and decrypt it based on the
public key of the server it has compiled into it. The contents would then
be used to initialize the secondary protocol (AES-128) defined.
A subsequent request would look like:
PUT /index.php
{
"session": "e91f5584152639c72d5358a05f9cd887584edaf9b6f06",
"security": {
"protocol": "aes-128",
"response": "aes-128"
}
"data": {
"params": "abcdef",
"buffer": "xxyyzzxxyyzzxxyyzz....xxyyzzxxyyzzxxyyzz"
}
}
In which the server will respond with:
{
"session": "e91f5584152639c72d5358a05f9cd887584edaf9b6f06",
"security": {
"response": "aes-128",
"protocol": "aes-128"
},
"data": {
"ts": "1481544610",
"params": "abcdef",
"buffer": "xxyyzzxxyyzzxxyyzz....xxyyzzxxyyzzxxyyzz"
}
}
Using a combination like rsa-1024/aes-128 is in line with the
security of some existing HTTPS environments; however, the manner in
which keys are exchanged and validated are less open - as they keys
need to be compiled into the client and server environments accordingly.
In essence; we have simply removed the overhead contained with TLS -
namely having to deal with raw X.509 certificates, certificate
authorities and the like.
So; what's next for µTLS?
First things first; I will build some examples based on the design
specified here. Putting the idea to the test should be able to rule
out if the protocol is feasible for use in real-world projects.
I have quite a lot of code optimized for micro-controllers that would
be usable with minimal modification.