Distributing IoTHub credentials using TPM

I bet, most of the time you have seen Azure IoT demos or most of the time you have programmed an IoT Uwp app yourself, you hard coded device credentials for the IoT hub. Yes, I’m guilty too 🙂

And this is, of course, a bad practice.

Not only, there is a risk these credentials are shared by checking them in into your version control system (like public Git). But it’s also inconvenient because, for each device running that production code, you will have to alter the credentials in the code and deploy again.

We could use configuration files. But this is still worthless in perspective of distribution.

We would like to pass the credentials to known devices separately, apart from the applications. We want to use a second channel. And this is possible with the current Windows IoT Core infrastructure.

All we need is a TPM. This is a Trusted Platform Module:

Trusted Platform Module (TPM) is an international standard for a secure cryptoprocessor, which is a dedicated microcontroller designed to secure hardware by integrating cryptographic keys into devices. TPM’s technical specification was written by a computer industry consortium called Trusted Computing Group (TCG). International Organization for Standardization (ISO) and International Electrotechnical Commission (IEC) standardized the specification as ISO/IEC 11889 in 2009.[1]

Why do we need it? Microsoft provides a separate mechanism to write credentials into the module which acts like a vault.

In this example, we will look at Windows 10 Core running on a Raspberry Pi. And we will use IoT Hub device credentials stored in a TPM.

Before we start, it’s good to know that we do not need AN ACTUAL TPM. You can do the same with the Raspberry PI which you are already having.

TPM Configuration

To configure your (imaginary) TPM on your Rpi, go to the Windows Device Portal (port 8080 of your device when the portal is activated). I use the Window 10 IoT Core Dashboard tool to access it very conveniently.

Once you are in, go to the TPM Configuration page.

Here you can select the actual TPM module that you have attached (if you have one) or you can select this “Software TPM Emulator”:

Press Install, now you have activated the TPM Module ( a reboot might be required).

Note: we just activated the usage of TPM, nothing more. We will reference this TPM in an app using source code, later on.

Next, go to the “Connect to Azure” page in the IoT Dashboard:

After you have entered valid Azure credentials, you can select an existing IoT Hub within your subscription. or you can create a new one.

After that, you will have to select a device:

Or, again, you can create one:

The last step is to search for a device with TPM in your network:

Once it is found, You can provision the private keys for this device, registered in this IoT Hub, to this TPM module:

After it is provisioned successfully, Check TPM Configuration page again:

As you can see, this page is now filled with the credentials gotten from the IoT Hub.

Accessing the TPM credentials using code

Let’s send some telemetry using these credentials. First, create a new UWP app and put a button on the main page:

<StackPanel>
  <TextBlock Name="txbTitle" Text="TPM Device Demo" Margin="5" FontSize="100" IsColorFontEnabled="True" Foreground="DarkOliveGreen" />
  <Button Name="BtnSend" Content="Connect and Send" Margin="5" FontSize="60" Click="BtnSend_Click" />
  <TextBlock Name="TbMessage" Text="---" FontSize="60" />
</StackPanel>

After that, use this code-behind source code and resolve the reference issues:

using Microsoft.Azure.Devices.Client;
using Microsoft.Devices.Tpm;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Core;

public sealed partial class MainPage : Page
{
  private int i;

  DeviceClient deviceClient;

  public MainPage()
  {
    this.InitializeComponent();

    var device = new TpmDevice(0);
    var hostName = device.GetHostName();
    var deviceId = device.GetDeviceId();
    var sasToken = device.GetSASToken();

    deviceClient = DeviceClient.Create(
                         hostName,
                         AuthenticationMethodFactory.
                         CreateAuthenticationWithToken(deviceId, sasToken),
                         TransportType.Amqp);
  }

  private async void BtnSend_Click(object sender, RoutedEventArgs e)
  {
    try
    {
      i++;

      var telemetry = new Telemetry
      {
        errorCode = 0,
        numberOfCycles = i,
      };

      var message = new Message(Encoding.ASCII.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(telemetry)));

      await deviceClient.SendEventAsync(message);

      await ShowMessage($"Message {i} is sent.");
    }
    catch (Exception ex)
    {
      await ShowMessage($"Exception {ex.Message}");
    }
  }

  private async Task ShowMessage(string text)
  {
    await Dispatcher.RunAsync(
      CoreDispatcherPriority.Normal, 
      () => {
              TbMessage.Text = text;
            });
  }
}

public class Telemetry
{
  public int errorCode { get; set; }
  public int numberOfCycles { get; set; }
}

It will be clear you need an extra NuGet package for the IoT Hub Client logic: Microsoft.Azure.Devices.Client. But you also need to reference this other NuGet package: Microsoft.Devices.Tpm:

Now compile and deploy this app on your Raspberry Pi. This app will not run on your own PC, the TpmDevice returns an empty string for Hostname, Deviceid, etc.

After deployment, press ‘Connect and Send’ and see how telemetry is sent:

You can check it out too in a Device Explorer or on the Azure Portal:

Conclusion

This is just an example to show how easy it is to communicate more securely. This TPM emulator is nice for demonstrations but once you want to secure the communication, you need actual TPM modules.

For more in-depth information about TPM on Windows 10, go to this Microsoft documentation.

 

3 gedachten over “Distributing IoTHub credentials using TPM

  1. This is a great and in-depth blog post about how one can set up and use TMP on Win 10 IoT Core, thanks! However, everything works fine for me, but when I restart my pi by plugging it out and in, and then run the app again, it does not seem to connect with the Azure IoT Hub anymore. Get a weird NotAuthorized exception. Sometimes it works again by re-provisioning it, but cannot get a handle on the actual root cause. Any suggestions?

    1. Hello Fanie, I just started the Rpi after two days of being shut down, I started the app and immediately I sent messages without any issue. I can not reproduce your error right now but I will keep an eye on it.

Reacties zijn gesloten.