nRF Cloud device provisioning

The nRF Device provisioning library enables a device to connect to nRF Cloud Provisioning Service, part of nRF Cloud Security Services. It abstracts and hides the details of the transport and encoding scheme that are used for the payload. The current implementation supports the following technologies:

  • AT-command based provisioning commands

  • Writing key-value pair based settings to the Settings storage

  • TLS-secured HTTP as the communication protocol

  • DTLS-secured CoAP as the communication protocol

  • Client authentication with JWT token

  • CBOR as the data format

Configuration

To enable the library, set the CONFIG_NRF_CLOUD and CONFIG_NRF_PROVISIONING Kconfig options.

Configuration options for HTTP

Configuration options for CoAP

Usage

The usage of the nRF Device provisioning library is described in the following sections.

Initialization

To use the library, you must initialize it. Call the nrf_provisioning_init() function and pass the following event callback handler to receive events from the library:

static void nrf_provisioning_callback(const struct nrf_provisioning_callback_data *event)
{
   /* Handle events received from the library here */
}

/* Initialize the provisioning client */
ret = nrf_provisioning_init(nrf_provisioning_callback);
if (ret) {
    LOG_ERR("Failed to initialize provisioning client: %d", ret);
    return ret;
}

Once initialized, provisioning can take place in one of the following two ways:

For an example of how to use the library, see the Cellular: nRF Device provisioning sample.

Provisioning

During provisioning, the device receives a set of commands from the server. This requires the device to deactivate LTE (putting the modem into offline mode) to be able to write the commands to the modem’s non-volatile memory. This is because the modem cannot be connected while any data is being written to its storage area.

When the CONFIG_NRF_PROVISIONING_AUTO_START_ON_INIT Kconfig option is set, the library initializes and starts provisioning according to the configured interval. When setting this option, you must ensure that it is called when the device has obtained a network connection and the modem is ready to communicate with the server. The interval is read from the storage settings and can be updated with a provisioning command like any other key-value pair.

During provisioning, the library first tries to establish the transport for communicating with the service. This procedure involves a (D)TLS handshake where the client establishes the correct server. The server uses the JWT generated by the device to authenticate the client. See Modem JWT for more information on client authentication.

The (D)TLS handshake happens twice:

  • Before requesting commands.

  • After the execution of the commands, to report the results.

After handling any received commands, the results are reported back to the server when either all the commands succeed or when an error occurs. If an error occurs, the results of all the commands that are successfully executed before the error and the erroneous result are reported back to the server. All successfully executed commands will be removed from the server-side queue, but if any errors occur, the erroneous command and all the remaining unexecuted commands are removed from the server-side queue. The log contains more information about the issue.

The following message sequence chart shows a successful provisioning sequence:

msc {
hscale = "1.5";
Owner,Server,Device;
Owner>>Server     [label="Provision: cmd1, cmd2, finished"];
Server<<Device    [label="Get commands"];
Server>>Device    [label="Return commands"];
Device box Device [label="Decode commands"];
Device box Device [label="Set modem offline"];
Device box Device [label="Write to non-volatile memory"];
Device box Device [label="Restore modem state"];
Server<<Device    [label="cmd1,cmd2, finished succeeded"];
}

The following message sequence chart shows a failing provisioning sequence:

msc {
hscale = "1.5";
Owner,Server,Device;
Owner>>Server     [label="Provision: cmd1, cmd2, cmd3, finished"];
Server<<Device    [label="Get commands"];
Server>>Device    [label="Return commands"];
Device box Device [label="Decode commands"];
Device box Device [label="Set modem offline"];
Device box Device [label="cmd1: Write to non-volatile memory"];
Device box Device [label="cmd2: Fails"];
Device box Device [label="Restore modem state"];
Server<<Device    [label="cmd1 success, cmd2 failed"];
Server>>Server    [label="Empty the command queue"];
Server>>Owner     [label="cmd2 failed"];
}

nRF Provisioning shell

To test the client, you can enable Zephyr’s shell and provisioning command, which allow you to control the client over UART. The feature is enabled by selecting CONFIG_NRF_PROVISIONING_SHELL.

Note

The shell is meant for testing. Do not enable it in production.

uart:~$ nrf_provisioning
nrf_provisioning - nRF Provisioning commands
Subcommands:
  now: Do provisioning now
  token: Get the attestation token
  uuid: Get device UUID
  interval: Set provisioning interval

The shell commands depend on the library being initialized in the application and the event handler being set.

Dependencies

This library uses the following nRF Connect SDK libraries:

It uses the following sdk-nrfxlib library:

It uses the following Zephyr libraries:

API documentation

Header file: include/net/nrf_provisioning.h
Source files: subsys/net/lib/nrf_provisioning/src/
nRF Device Provisioning API