Aaron Ardiri
[Valid RSS] RSS/XML feed
198 entries available (show all)

 

Internet of Things (IoT)
   

PLEASE TAKE A MOMENT TO FOLLOW MY NEW VENTURE:
 
RIoT Secure AB
 
ALL SECURITY RELATED TOPICS ON IoT wILL BE POSTED THERE


2016-12-15
>> µTLS - DEFINING LIGHTWEIGHT SECURITY FOR IoT (PART 3)

There comes a time when one must write code for micro-controllers, nothing like good old C.

In the continuing effort to create µTLS (micro TLS) - it is finally time to build the foundations of our micro-controller client. I've written a number of sketches for Arduino and similar devices over the years so I will bring all my experiences into play to build a benchmark platform for our modules. A key design component I wished to integrate was easy to follow logic and code segmenting.

I went with a simple state engine for managing the main execution loop.

    #define STATE_IDLE    0
    #define STATE_SESSION 1
    #define STATE_PING    2
    
    int        app_state;
    uint32_t   app_ts;
    uint32_t   app_ts_ping;
    uint32_t   app_ts_local;

While not all micro-controllers have a built in RTC (real time clock); we will simulate one based on the response we get from our server and also use the timestamp to decide when to change the application state. In essence; we'll either be idling - in which case we could be reading sensors et al, establishing a new session or pinging the server to provide updates during a session.

    void setup()
    {
      // initialize our app_ts_local
      app_ts       = 0;
      app_ts_ping  = 0;  // we do not know these values at this point
      app_ts_local = millis();
    
      // first task is to initialize a session with server
      app_state = STATE_SESSION;
    }

Our setup routine simply initializes the state variables and tells us to establish a session.

    void loop() 
    {
      uint32_t ts;
      
      // update the app_ts, based on CPU milliseconds
      ts = millis();
      app_ts       += (ts - app_ts_local) / 1000;        // whole seconds
      app_ts_local  = ts - ((ts - app_ts_local) % 1000); // carry the modulus
    
      switch (app_state)
      {
        case STATE_IDLE:
             // is it time to ping the server again?
             if (app_ts >= app_ts_ping) app_state = STATE_PING;
             else delay(500); // just kill some time while we wait
             break;
             
        case STATE_SESSION:
             session_create();
             break;
        
        case STATE_PING:
             session_ping();
             break;
      }
    }

I chose to use a WiFiShield for my sketch; however, you could use an EthernetShield if desired. There are plenty of examples available on how to act as a HTTP client; so I will not go into the details in this blog post, the code will be available for you to review and see how to correctly deal with timeouts, disconnections and other twiddly bits and pieces (you will thank me later).

Since we decided that to send binary data safely over an ASCII transmission using JSON within the protocol requires the use of Base64 - I whipped together a nice and resource efficient variant for us to use. I was able to isolate being able to encode and decode small chunks without having to allocate memory, something that is a limited resource on these devices.

    void b64_encode_chunk(byte *src, byte cnt, char *dst);
    void b64_encode(byte *src, int cnt, char *dst);
    void b64_encode_stream(Stream *s, byte *src, int cnt);
    int  b64_encode_len(int len);
    
    void b64_decode_chunk(char *src, byte cnt, byte *dst);
    void b64_decode(char *src, int cnt, byte *dst);
    void b64_decode_stream(Stream *s, char *src, int cnt);
    void b64_decode_stream_hex(Stream *s, char *src, int cnt);
    int  b64_decode_len(byte *src, int len);

While there are plenty of libraries available to do things; you may want to extract the bits and pieces you need so it doesn't bloat out your sketch. In some cases, you may even need to take the more brutal approach for dealing with stuff like JSON, over using a library.

    const char KEY_SESSION[] = "\"session\":";
    
    ...
    
    strcpy(needle, KEY_SESSION); p = strstr(buf, needle);
    if (p != NULL)
    {
      // we need to make a duplicate of the string between the '"'
      p += strlen(needle);
      p = strchr(p, '"'); p++; // find the first  '"', skip
      *(strchr(p, '"')) = 0;   // find the second '"', make \0
      strcpy(app_session, p); 
                  
    #ifdef ENABLE_DEBUG
      Serial.print(F("** found session: "));
      Serial.println(app_session); 
    #endif              
    }

Scared of C pointers?

Then micro-controller programming at this level probably isn't for you. There are some nifty libraries around; like arduino-json but even the footprint is too large for our needs here. Since we control both the server and client; we can take a few shortcuts and utilize basic string searching using new lines as key delimiter detection within the transmission of data between the server and client.

After piecing everything together (took me a while), my Arduino UNO could talk to my server.

    :: microTLS (none/none)
    =======================
    (c) RIoT International Pty Ltd
    build: Dec 15 2016
    
    :: attempting to connect to WiFi network 
    ** connected to WiFi
       SSID:       RIoT-eu
       IP Address: 192.168.1.196
       NetMask:    255.255.255.0
       Gateway:    192.168.1.1
    
    app state:    1
    current time: 0
    session_ping: 0
    :: attempting connection to server
    ** connected
    -- request:
    POST /xxx/index.php HTTP/1.1
    Host: xxx.xxxxxxxx.xxx
    User-Agent: Arduino/1.0
    Connection: close
    Content-type: application/x-www-form-urlencoded
    Content-Length: 118
    
    {
      "guid": "ffa90e64-f3e2-4697-b98c-e3c13d1b2362",
      "security": {
        "protocol":"none",
        "response":"none",
        "protocol_sub":"none"
      }
    }
    -- response:
    HTTP/1.1 200 OK
    Date: Thu, 15 Dec 2016 10:58:06 GMT
    Server: Apache
    Content-Length: 195
    Connection: close
    Content-Type: application/json
    
    {
        "session": "e91f5584152639c72d5358a05f9cd88758527740d09bb",
    ** found session: e91f5584152639c72d5358a05f9cd88758527740d09bb
        "security": {
            "response": "none",
            "protocol": "none"
        },
        "data": {
            "ts": "1481799488"
    ** found ts: 1481799488
        }
    }
    
    :: done
    app state:    0
    current time: 1481799488
    session_ping: 1481799488
    app state:    2
    current time: 1481799488
    session_ping: 1481799488
    :: attempting connection to server
    ** connected
    -- request:
    PUT /xxx/index.php HTTP/1.1
    Host: xxx.xxxxxxxx.xxx
    User-Agent: Arduino/1.0
    Connection: close
    Content-type: application/x-www-form-urlencoded
    Content-Length: 173
    
    {
      "session": "e91f5584152639c72d5358a05f9cd88758527740d09bb",
      "security": {
        "protocol":"none",
        "response":"none"
      },
      "data": {
        "buffer":"c2VuZGluZyBhIG1lc3NhZ2Ugb3ZlciBtaWNyb1RMUw=="
      }
    }
    -- response:
    HTTP/1.1 200 OK
    Date: Thu, 15 Dec 2016 10:58:12 GMT
    Server: Apache
    Content-Length: 227
    Connection: close
    Content-Type: application/json
    
    sending a message over microTLS
    {
        "session": "e91f5584152639c72d5358a05f9cd88758527740d09bb",
        "security": {
            "response": "none",
            "protocol": "none"
        },
        "data": {
            "ts": "1481799494"
    ** found ts: 1481799494
        }
    }
    
    :: done
    app state:    0
    current time: 1481799494
    session_ping: 1481799794
    

For the sake of readability; I manually edited the data being sent up (highlighted in bold) for the blog, the real messages are all on a single line using as little data as possible. It should be clear in the console log where our code was able to find various tokens in the JSON (session, ts) - parsing them for storage in our application. The final piece of the puzzle is to know when to synchronize next; we have defined a constant of 300 seconds (5 minutes) from the last request.

We now now have a fully functional sketch deployed on the Arduino UNO that can establish a HTTP connection to our server; do base64 encoding/decoding, perform POST and PUT requests and brutally parse the JSON responses. We must remember that it has absolutely no security yet.

So; how big is the application and how much memory does it require just to do this?

    Sketch uses 16,910 bytes (52%) of program storage space. 
    Global variables use 1,527 bytes (74%) of dynamic memory, 
    leaving 521 bytes for local variables. Maximum is 2,048 bytes.

There are a number of tricks; namely using PROGMEM to free up dynamic memory:

    Sketch uses 17,890 bytes (55%) of program storage space. 
    Global variables use 487 bytes (23%) of dynamic memory, 
    leaving 1,561 bytes for local variables. Maximum is 2,048 bytes.

Removing debugging (not needed for deployment) also gives more RAM and removes some code:

    Sketch uses 13,604 bytes (42%) of program storage space. 
    Global variables use 443 bytes (21%) of dynamic memory, 
    leaving 1,605 bytes for local variables. Maximum is 2,048 bytes.

On an Arduino UNO (and similar micro-controllers) this means there is just over half the program storage space available and the ability to use just over 1.5Kb for local variables. Taking the issue of CPU speed out of the equation; the next question is what can we put in this limited space that actually can allow for secure communication between the micro-controller and the server?

Well, that is plenty of resources - we can definitely do a lot with that! I accept the challenge!

In the next entry we'll look at doing just that - I have already written a rot13 module; but that one doesn't really provide much cryptographic value to any project. I have a few more modules in mind that will be candidates for providing real security on micro-controllers with limited resources. I will leave it up to you to tweak the Arduino sketch to support rot13 - shouldn't take much.

The source code for the microTLS server, two modules and the Arduino client are available below:

µTLS (micro TLS) SERVER (alpha version)

µTLS (micro TLS) CLIENT (alpha version)


 

advertisement (self plug):
need assistance in an IoT project? contact us for a free consultation.

 



µTLS - defining lightweight security for IoT (part 4)
 
µTLS - defining lightweight security for IoT (part 2)

DISCLAIMER:
All content provided on this blog is for informational purposes only.
All comments are generated by users and moderated for inappropriateness periodically.
The owner will not be liable for any losses, injuries, or damages from the display or use of this information.