Pairing - Decentral Access Control

In Nabto Edge, Public Key Authentication is used for authenticating peers. Devices have an access control list with allowed clients’ public keys, clients have a list of known device public keys. The process of adding a client public key to the device access control list and adding a device public key to a client’s known devices list is denoted pairing.

The Nabto Edge Embedded SDK’s IAM module provides facilities for performing pairing in a secure and robust way. All of these are used through a set of Nabto Edge CoAP services exposed by the target device, invoked by the Nabto Edge Client. A client helper component is provided that wraps invocation of these CoAP endpoints to simplify application development, see the Android IAM Util and iOS IAM Util, respectively.

4 different pairing modes are implemented by the IAM module, these are described in the following sections. A device can be configured with multiple pairing modes - e.g. to support bootstrap scenarios with special handling of the first paired user.

Key Exchange Mechanisms

When exchanging public keys, care must be taken to prevent man-in-the-middle attacks: An attacker may impersonate the intended target device or inject a public key different from the true pairing client’s. The exchange of public keys must happen through a pairing method designed to prevent such attacks.

Each of the pairing modes described below uses one of the following two key exchange mechanisms:

Password based pairing

Using PAKE and a password known by client and device, a secure session is established between the two. Public keys are exchanged in the secure session and access control lists updated. This mechanism supports both local (discovery based) pairing, direct pairing (using the device IP address) and remote pairing.

The password must somehow be exchanged between the device and client prior to the pairing step, for instance in one of the following ways:

  • if the device has a display, it can be used to show the pairing password (directly or as a QR code)
  • the password can be printed on a label (directly or e.g. as a QR code)
  • it can be set by an administrator and passed on to the new user

Local (trusted LAN) pairing

The client connects to a device on their common LAN. The user must ensure LAN communication can be trusted, at least for the duration of the pairing process. Public keys are exchanged on the trusted LAN and access control lists updated.

Pairing Modes

The key exchange mechanisms are combined with different strategies for who are allowed to pair - resulting in modes: Invitation based pairing requires a specific user to be created before pairing is possible. Open pairing modes do not require a pre-existing user - pairing takes place on the initiative of the user who wants to pair.

Local open pairing

Local open pairing uses the trusted local network (LAN) mechanism. No password is required for pairing and no invitation is needed, anybody on the LAN can initiate pairing.

This approach is often used in less security concerned consumer scenarios: Anybody who can discover a device can pair as the role configured by the admin, typically a less-capable guest role. Such limited guest accounts can then be granted further access by the administrator after pairing as necessary.

See implementation details for further information.

Password open pairing

In this mode a device has set a password which can be used in the pairing process to grant a client access to the device. The client can pair remotely to the device if necessary; it is not necessary to be on the same LAN.

Open means that the pairing password is the same for all clients that need to pair with the device. This is like a WiFi password: Everyone who knows the password is allowed to connect. Compare with Password invite pairing.

See implementation details for further information.

Local initial pairing

This is a special open pairing: In this mode, the initial user can be paired on the local network without providing a username or password - and only the initial user. This is a typical bootstrap scenario to pair the admin user (device owner).

After the initial user is paired, no further users are allowed to be paired with this mode - so it must be combined with other modes to allow other users to be granted access.

See implementation details for further information.

Password invite pairing

In the Password invite pairing mode a user is required in the system to be able to pair: An existing user (or the system autonomously) creates a username and password that is somehow passed to the new user (an invitation).

The invited user pairs with the device using the provided username and password. The pairing can only be performed once. This pairing mode is typically used in industrial deployment where stricter access control is needed. Compare with the password open pairing mode where a common global password is used for any user who wants to pair.

See implementation details for further information.

Side-Channel Pairing

In addition to the interactive pairing scenarios that can be implemented using the above, vendors can use any alternative means that securely transfers the necessary information between the two peers. For instance, the vendor can perform Nabto pairing using bluetooth if such is available in client and device.

Sometimes vendors want to “pre-pair” a device by adding a public key to the device access control list directly on the factory. That is, when the device boots at the user, this pre-paired “super-admin” user already has access.

The convenience of pre-paired keys comes with a drawback: If the super-admin’s central private key corresponding to the pre-paired public key is compromised, the attacker will have access to all pre-paired devices. JWT can be used to achieve the same in a less security sensitive way.

Pairing Mode Implementation

The necessary configuration for the modes outlined above are described in the following sections.

Local open pairing implementation

To perform Local open pairing, the client invokes the CoAP service POST /iam/pairing/local-open. This can invoked through IamUtil.pairLocalOpen() on iOS and IamUtil.pairLocalOpen() on Android.

This CoAP endpoint requires unpaired users to be associated with the IAM action IAM:PairingLocalOpen. Such policy could look as follows:

"Policies" : [
      {
         "Id" : "Pairing",
         "Statements" : [
            {
               "Actions" : [
                  "IAM:GetPairing",
                  "IAM:PairingLocalOpen"
               ],
               "Effect" : "Allow"
            }
         ]
      }, ...

In the IAM configuration, OpenPairingRole defines the role assigned to the user when successfully paired, for example:

{
  "Version": 1,
  ...
  "OpenPairingRole": "Guest",
  ...
}

This pairing mode can be enabled and disabled globally at runtime through the API function nm_iam_set_local_open_pairing(). The programmatically set value and the IAM configuration must both evaluate to true to allow pairing to take place. Per default the global value is off, meaning that the application must enable this to allow local open pairing, even if the IAM configuration allows it.

Password open pairing implementation

To perform Password open pairing, the client invokes the CoAP service POST /iam/pairing/password-open. This can invoked through IamUtil.pairPasswordOpen() on iOS and IamUtil.pairPasswordOpen() on Android.

This CoAP endpoint requires unpaired users to be associated with the IAM action IAM:PairingPasswordOpen. Such policy could look as follows:

"Policies" : [
      {
         "Id" : "Pairing",
         "Statements" : [
            {
               "Actions" : [
                  "IAM:GetPairing",
                  "IAM:PairingPasswordOpen"
               ],
               "Effect" : "Allow"
            }
         ]
      }, ...

In the IAM configuration, OpenPairingRole defines the role assigned to the user when successfully paired, for example:

{
  "Version": 1,
  ...
  "OpenPairingRole": "Guest",
  ...
}

This pairing mode can be enabled and disabled globally at runtime through the API function nm_iam_set_password_open_pairing(). The programmatically set value and the IAM configuration must both evaluate to true to allow pairing to take place. Per default the global value is false, meaning that the application must enable this to allow open password pairing, even if the IAM configuration allows it.

Local initial pairing implementation

To perform Local initial pairing, the client invokes the CoAP service POST /iam/pairing/local-initial. This can invoked through IamUtil.pairLocalInitial() on iOS and IamUtil.pairLocalInitial() on Android.

This CoAP endpoint requires unpaired users to be associated with the IAM action IAM:PairingLocalInitial.

After the administrator is paired, this action allows no further users to be paired - so a separate mode must be used to allow subsequent pairing (typically to a less capable role, e.g. Guest). For instance, IAM:PairingPasswordOpen can be added as well to allow subsequent users to be paired using the Open Password pairing mode.

Such policy could look as follows:

"Policies" : [
      {
         "Id" : "Pairing",
         "Statements" : [
            {
               "Actions" : [
                  "IAM:GetPairing",
                  "IAM:PairingLocalInitial",
                  "IAM:PairingPasswordOpen"
               ],
               "Effect" : "Allow"
            }
         ]
      }, ...

In the IAM configuration, InitialPairingUsername defines the default username for the initially paired user. This username must have been defined in the IAM configuration with a reference to the desired role, typically a role with admin privileges.

For the above IAM example that adds IAM:PairingPasswordOpen to the policy, the OpenPairingRole configuration parameter is needed to define the role assigned to subsequent users paired.

An IAM configuration example for these two parameters that grants admin privileges to the initial user and guest privileges to subsequent users:

{
  "Version": 1,
  ...
  "InitialPairingUsername": "admin",
  "OpenPairingRole": "Guest",
  ...
}

The referenced admin user can be preconfigured as follows:

   struct nm_iam_user* admin = nm_iam_state_user_new(initialUsername);

    nm_iam_state_user_set_role(admin, "Administrator");
    nm_iam_state_add_user(state, admin);

This pairing mode can be enabled and disabled globally at runtime through the API function nm_iam_set_local_initial_pairing(). The programmatically set value and the IAM configuration must both evaluate to true to allow pairing to take place. Per default the global value is false, meaning that the application must enable this to allow local initial pairing, even if the IAM configuration allows it.

Password invite pairing implementation

To perform Password invite pairing, the client invokes the CoAP service POST /iam/pairing/password-invite. This can invoked through IamUtil.pairpasswordinvite() on iOS and IamUtil.pairPasswordInvite() on Android.

This CoAP endpoint requires unpaired users to be associated with the IAM action IAM:PairingPasswordInvite. Such policy could look as follows:

"Policies" : [
      {
         "Id" : "Pairing",
         "Statements" : [
            {
               "Actions" : [
                  "IAM:GetPairing",
                  "IAM:PairingPasswordInvite",
               ],
               "Effect" : "Allow"
            }
         ]
      }, ...