Security in Nabto P2P/IoT solutions

Security in IoT and especially in home security solutions has been subject for several recent articles and debate, for instance see http://thenewstack.io/snooping-webcam-reveals-security-dangers-internet-things/.

Since the article above covers the general security issues of P2P, the same concerns of course apply to Nabto based solutions – this post addresses these concerns and summarizes the security principles of our platform, some of it applies to P2P solutions in general.

Basically, to allow a peer-to-peer connection to be established to a device, such as a camera, the camera must communicate with a central service that knows about the camera’s network configuration. This is not any different than in e.g. IP telephony where the IP phone central knows about each IP phone’s network configuration and needs to communicate periodically with each IP phone to allow other peers to make calls to it:

When a Nabto enabled device (e.g. a P2P IP camera) is turned on, it will try to register itself with its associated central services. Our approach to this is to use DNS – each Nabto enabled device has an associated DNS hostname, for instance <some-id>.p2p.vendor.net. This DNS name resolves to the Nabto “phone central” services, we denote this the “Nabto basestation”:

nabto-devices-white

The registration with the basestation takes place using strong cryptography using HMAC/SHA256 and AES128 with a per device unique shared secret. This allows a secure, private channel to be setup between the basestation and the device; all subsequent remote communication with the device is then encrypted for confidentiality and integrity. This approach without the need for asymmetric cryptography on the device enables Nabto to work on even the most resource constrained devices, e.g. sub 1-dollar 8-bit MCUs.

The client that communicates with the device is authenticated through an RSA X509 certificate. When a client initiates a connection towards a device, a secure channel is first established between client and basestation using a regular RSA based TLS handshake. A session key is then established and exchanged between client and device, along with IP information to allow a P2P connection attempt.

Once a connection is established, the device owner controls who accesses the device, the traffic cannot be manipulated and an attacker cannot intercept the communication.

nabto-security

This is all good as long as you can trust the owner of the basestation and that what I said above is actually true about the device code. The Nabto platform allows vendors to host their own private basestation – and most of our biggest customers indeed do that today. This means that Nabto is completely out of the loop. And that the vendor can have their servers located in their desired geographical region – so no need for communication with seemingly random hosts in e.g. China. The vendor can hence have a trust relationship solely with their customers (the end-user), the end-user sees no peculiar traffic between their device and an unknown 3rd party.

Our device SDK is open source, you can download everything on Github so you can see exactly what the communication is about. Of course this is not a guarantee – the individual vendor could in principle change the source code. But if you inspect the communication  with e.g. Wireshark and correlate with the available source code, the task for understanding the individual vendor’s product for an analyst is indeed simpler.

With all the above being said – much of the current discussion about P2P security is about the owner of the device not being able to turn P2P access off: It is of course up to the vendor to control how to activate the Nabto P2P functionality – but we make it simple to do so, we have a single “master switch”; if not turned on, there is absolutely no P2P related communication taking place.

For more information on security in the Nabto platform, don’t hesitate to contact us on support@nabto.com or take a look in our security guide TEN036 Security in Nabto Solutions.

Blog launched!

Last week we launched our blog, something we have wanted for a long time: A place to share thoughts from the team as well as cool projects realized using the Nabto platform. In the first such post, Marcus describes how he provided his solar cell project with remote access in a few simple steps using Nabto.

Don’t hesitate to contact us if you have some good ideas for a project to write about or implement here! Or if you already have made a cool Nabto enabled project, let us know and we will be happy to write about it! Use the chat on www.nabto.com or write to support@nabto.com.

Ulrik and the rest of the Nabto team

The SunPi control center

Ever since I first build my solar powered Raspberry Pi system, called the SunPi, I wanted to be able to remote control it.

More specifically, in the summertime, when the sun shines heavily the battery would be filled within an hour after sunrise. The rest of the day, the charge controller would simply waste/curtail excess energy by dumping it as heat.
Instead of doing that I wanted to use this energy for something. Specifically I wanted to be able to remote control a relay such that I could activate whatever device I had lying around.

total_overview

Overview of the SunPi system

To determine whether or not to activate the relay I had to be able to read the voltage level which is equivalent to how filled the battery is. I did this using a INA219 current sensor, some Python and plotted it here. But I really wanted to have everything on a single page such that I could quickly determine whether or not to activate the relay. I wanted to be able to access this control center from anywhere and in a secure way. With Nabto I found the solution.

How Nabto works

nabto_overview

Overview of the Nabto framework

As seen in the above figure the client side (e.g. the device you are reading this on) has HTML, CSS and JavaScript running when you visit the SunPi control center. Altering a slider in the HTML calls a JavaScript function which in turn sends a Nabto request to the device side of things.
In this case the device is a Raspberry Pi running some compiled C code. For our power and voltage readings (more below) a Python script is called from within the C code.
That is basically all there is to the framework.

To get a better feel of how to add functionality I will walk through

  • Controlling a GPIO pin
  • Retrieving data

Note that these examples build on the default html_dd (Client side) and this RPi demo (Device side).

Controlling a GPIO pin

HTML

We start by creating a slider with a unique id (rgb-r in this case) containing the OFF and ON options.

<li>
  <h2>Red</h2>
  <div class="ui-li-aside">
    <select id="rgb-r" data-role="slider">
      <option value="off">OFF</option>
      <option value="on">ON</option>
    </select> 
<li>>

JavaScript

When the slider with the rgb-r id is toggled, the accompanying JavaScript-script is activated.

$("#rgb-r").change(function(){
  var state = $(this).val() === "off"?0:1;
  jNabto.request("light_write.json?light_id=1&light_on="+state, setLight_r); 
}); 

Where the setLight_r function shifts the actual slider.
What is perhaps more interesting is the jNabto.request part. The jNabto requests are defined in the unabto_queries.xml file and the light_write.json used above look like this

<query name="light_write.json" description="Turn light on and off" id="1">
  <request>
    <parameter name="light_id" type="uint8"/>
    <parameter name="light_on" type="uint8"/>
  </request>
  <response format="json">
    <parameter name="light_state" type="uint8"/>
  </response>
</query>

As seen, the request sends the two light_id and light_on variables containing information about which pin/light we are dealing with and which state (light_on) we want it in. After this, we expect to receive a json format response, specifically the light_state the pin has been set to. We notice that the query id is 1.

C code

On the device side we arrive at case 1 (in unabto_application.c) since the light_write.json has id = 1.

case 1: {
    uint8_t light_id;
    uint8_t light_on;
    uint8_t light_state;

    // Read parameters in request
    if (!buffer_read_uint8(read_buffer, &light_id)) {
        NABTO_LOG_ERROR(("Can't read light_id, the buffer is too small"));
        return AER_REQ_TOO_SMALL;
    }
    if (!buffer_read_uint8(read_buffer, &light_on)) {
        NABTO_LOG_ERROR(("Can't read light_state, the buffer is too small"));
        return AER_REQ_TOO_SMALL;
    }

    // Set light according to request
    light_state = setLight(light_id, light_on);

    // Write back pin state
    if (!buffer_write_uint8(write_buffer, light_state)) {
        return AER_REQ_RSP_TOO_LARGE;
    }
    return AER_REQ_RESPONSE_READY;
}

Most of this is for error logging, we only need to focus on the setLight function and how we plan on sending a message back to the client side afterwards.
The setLight function looks like this

// Set GPIO pin and return state,
uint8_t setLight(uint8_t id, uint8_t onOff) {
    theLight[id] = onOff;

    NABTO_LOG_INFO(("Nabto: %s turned %s!\n", pin_name[id], on_off[theLight[id]]));

#ifdef __arm__
    /* Toggle GPIO pins on Raspberry Pi	*/
    //Change pin output according to id and theLight state

    if (theLight[id]){
        //Activate pin
        digitalWrite(pin_id[id], LOW);
    }
    else if(theLight[id]==0){
        digitalWrite(pin_id[id], HIGH);
    }
#endif

    return theLight[id];
}

Where we toggle the chosen pin on or off depending on the light_on variable passed from the client.

When we sucessfully set the actual pin we write back the pin state to the client using the buffer_write_uint_8 command. And that is bascially all you need to control a GPIO pin on the Raspberry Pi using the Nabto framework.

Retrieving data

HTML

The HTML code for retrieving data is basically just a button which signals the JavaScript to do a certain task, in this case we are dealing with id=”ina_update” (remember, we are using a INA219 current sensor).

<li>
  <input type="button" id="ina_update" data-icon="refresh" value="Read Voltage and Power"/>
</li>

JavaScript

The accompanying JavaScript function look like this

$("#ina_update").click(function() {
  queryINA219($(this));
});

where

function queryINA219(input) {
  jNabto.request("ina_data.json?", function(err, data) {
    if (!err) {
      temp_power = data.power_w/10000

      // Check if negative
      if (temp_power > 100)
      {
        temp_power = temp_power - 200
      }

      input.val("Voltage: " + (data.voltage_v/10000).toFixed(2) + "V, Power: " + temp_power.toFixed(2) + "W").button("refresh");
    }
  });
}

contain the ina_data.json jNabto request. Again we check the unabto_queries.xml file and make sure that

<query name="ina_data.json" description="Read voltage and power status" id="3">
  <request>
  </request>
  <response format="json">
    <parameter name="voltage_v" type="uint32"/>
    <parameter name="power_w" type="uint32"/>
  </response>
</query>

the ina_data.json query id is 3.

C code

The request is sent to the device side where we end up in case 3 because the ina_data.json request has id = 3.

case 3: {
    // Get voltage from INA219
    getINA219_data(&voltage, &power);

    NABTO_LOG_INFO(("Nabto: Read voltage=%f and power=%f\n", voltage, power));

    // Write back data
    if (!buffer_write_uint32(write_buffer, voltage*10000)) 
    {
        return AER_REQ_RSP_TOO_LARGE;
    }

    // Prepare for negative numbers. This will be converted back in the html_dd app.js file
    if (power<0)
    {
        power = power + 200;
    }
            
    // Write back data
    if (!buffer_write_uint32(write_buffer, power*10000))
    {
        return AER_REQ_RSP_TOO_LARGE;
    }
    return AER_REQ_RESPONSE_READY;
}

As seen above, the power data needs special preparation since we are writing uint32 (unsigned, i.e. numbers are always positive). When the battery charges the power is defined to be positive and when it discharges it is of course negative. Since my solar panel has a maximum rated power of 100W (which it never reaches) and my maximum power consumption is 10W at any given time, I simply add 200 to the power measurement. I made sure to undo this addition in the accompanying JavaScript as seen above (// Check if negative).
Finally we take a look at the getINA219_data function,

// Get INA219 data
void getINA219_data(float* voltage, float* power){

    FILE *fp;
    char path[1035];
    /* Open the command for reading. */
    fp = popen("sudo python path/to/ina219_python_c.py", "r");

    if (fp == NULL) {
        NABTO_LOG_INFO(("Failed to run Python script\n"));
        exit(1);
    }
    /* Read the output a line at a time - output it. */
    int k = 0;
    while (fgets(path, sizeof(path)-1, fp) != NULL) {
        k = k + 1;
        if (k==1){
            *voltage = atof(path);
        }
        else if(k==2){
            *power = atof(path);
        }
    }
    /* close */
    pclose(fp);
}

The function calls a Python script which print out two lines of data. The lines contain the voltage and the power flowing in or out of the SunPi battery, respectively.
The data is then sent back to the client side using the buffer_write_uint32t command as seen above.
These are the building stones for how to write a simple Nabto application. After expanding on this a bit I finally had my control center.

The SunPi control center

control_center

The control center enables the user to control a RGB LED as well as a single relay or retrieve the voltage and power flowing into (or out) of the SunPi battery. It is also possible to retrieve the internal temperature of the SunPi.

Thus I can now simply access the Nabto SunPi control center (just click on guest to try it out. NOTE: no longer available) and then check the voltage. The battery is full when the voltage is above ~13V. If that is the case I can activate the relay or use the extra power for an RGB LED.

The full code is available on Github.

That’s all!