7.2. Factory Provisioning Tool
7.2.1. General overview
Anjay comes with a simple Python script that makes factory device provisioning easier. The script supports:
Generation of SenML CBOR encoded packet with basic object information read by Anjay.
Creation of self-signed certificates.
Loading configuration to device (currently supports Nordic boards).
Automatic device onboarding in the Coiote server.
7.2.2. Provisioning tool
The provisioning tool is a small script that the user will interact with during the factory provisioning process. It uses the Factory Provisioning library that we will talk about in the next section.
The script can be found in
The script takes many different parameters as arguments to allow some customisation. Let’s take a closer look:
-c, –endpoint_cfg - path to the configuration file with the object information to be loaded to the device. The file is in the format of a Python dictionary that is evaluated by the library and represents LwM2M objects to be loaded to the device. In addition to the standard Python data types (
bytes) to represent values of resources in the object, the user can use
Objlinkclass to represent objlnk resource type. The constructor for this class is as following:
class Objlink: def __init__(self, ObjID, ObjInstID): self.ObjID = ObjID self.ObjInstID = ObjInstID
So for instance
Objlink(66, 0)would represent a object link
Sample configuration can be found in
The provisioning tool is NOT intended to be safe to use with arbitrary input data. It is only intended for convenience when working with files created locally by trusted parties.
The input text file (“endpoint_cfg”) is evaluated as Python code, and as such, running the code from provisioning tool with untrusted input may lead to arbitrary operations being performed on the computer.
-e, –URN - This is the name of the device that will be used during registration to the Coiote Server. The name should be unique for the instance of Coiote Server we will register the device to.
-s, –server - This is a JSON file with server information needed for registration process. Those include:
url - url of the Coiote Server, if missing a default value
port - port number communication with the REST API, if missing a default value
8087is used. Please note that this is not the port number used by the endpoint device for communication with the Coiote server and rather a port number used by the REST API.
domain - name of the domain under which to register the device. There is no default value and this needs to be provided by the user if a registration process is performed.
Sample configuration can be found in
-t, –token - Access token for REST authorization to the Coiote server. The generation of this token is explained in the Coiote documentation. In Coiote click on the question mark in the top right corner, then Documentation -> User. The description can be found in Rest API -> REST API authentication section.
-C, –cert - Path to the JSON file containing information for the generation of a self signed certificate. The provisioning tool supports those JSON entries:
Holds a 2-character ISO format country code. Represents attribute C in certificate subject.
Represents attribute ST in certificate subject.
Represents attribute L in certificate subject.
Represents attribute O in certificate subject.
Represents attribute OU in certificate subject.
Holds email address.
Represents attribute CN in certificate subject.
Holds serial number attribute in the certificate subject.
Represents validity of certificate in seconds.
Represents length of the RSA key used during certificate creation.
Represents a digest algorithm used during certificate signing.
Sample configuration can be found in
-k, –pkey - Path to the endpoint private key in DER format, ignored if CERT parameter is set.
-r, –pcert - Path to the endpoint private cert in DER format, ignored if CERT parameter is set.
-p, –scert - Path to the server public cert in DER format.
The server public certificate in DER format can be acquired using openssl client:
echo -n | openssl s_client -connect SERVER:PORT | openssl x509 -outform der > CERTIFICATE.der
or converted from PEM format using:
openssl x509 -outform der -in CERTIFICATE.pem -out CERTIFICATE.der.
7.2.3. Factory Provisioning library
To better understand the provisioning process we will look into the implementation of the Factory Provisioning library.
The Python library for factory provisioning can be found in
The main class of the library that the user will interact with is the
class. The constructor for this class takes a few different arguments:
class FactoryProvisioning: def __init__(self, endpoint_cfg, endpoint_name, server_info, token, cert_info):
endpoint_cfg is the path to the file with the device configuration. Corresponds
to the argument of the same name from the provisioning tool.
The next parameter is
endpoint_name. This is the unique name of the device used
during registration. Corresponds to the URN argument from the provisioning tool.
server_info is the path to the file with Coiote server information. Corresponds
to server argument from the provisioning tool.
token parameter is a token used to authenticate to the REST API. Corresponds
to the argument fo the same name from the provisioning tool.
cert_info parameter can be used to pass the path to a file containing information
used during generation of a self signed certificate. This parameter corresponds to
cert argument from the provisioning tool.
endpoint_name can be set to
automatic registration to the Coiote server won’t be done. Also cert_info
parameter can be
None if the user won’t create a self signed certificate using
the factory provisioning library or security mode used will be different then
The user can extract the information about used Security Mode set in
using a class method
get_sec_mode(). This returns a string containing one
of three values: “psk”, “cert”, “nosec”.
If Certificate is used as a Security Mode in the Security object definition,
then before calling
user should call
set_server_cert()function to pass a path to a DER formatted file containing server’s certificate,
generate_self_signed_cert()should be called or pre-generated certificates should be supplied by calling
set_endpoint_cert_and_key()with a path to device’s private key and public certificate.
To perform the factory provisioning of the device the user should call
FactoryProvisioning class. This function will generate a configuration
file in the format os SenML CBOR (the file will be called “SenMLCBOR” and writen to disk). This
configuration will be uploaded to the device together with the certificates (either
self signed client certificates or the cerificate pointed by
and also the server certificate set using
register() function can be used to automatically register the device
to the Coiote Server. Please note that if Certificate was used as a Security Mode
then the device public certificate should uploaded by hand in to the Coiote Server.
The self-signed certificates are generated to the
We can now take a look at the provisioning tool implementation to see how this API can be used:
try: fcty = fp.FactoryProvisioning(args.endpoint_cfg, args.URN, args.server, args.token, args.cert) if fcty.get_sec_mode() == 'cert': if args.scert is not None: fcty.set_server_cert(args.scert) if args.cert is not None: fcty.generate_self_signed_cert() elif args.pkey is not None and args.pcert is not None: fcty.set_endpoint_cert_and_key(args.pkey, args.pcert) fcty.provision_device() if args.server is not None and args.token is not None and args.URN is not None: fcty.register() ret_val = 0 except ValueError as err: print('Incorrect configuration:', err) except ConnectionError as err: print('Coiote server error:', err) except requests.HTTPError as err: print(err) except OSError as err: print(err) except RuntimeError as err: print(err) except: print('Unexpected error, abort script execution') finally: sys.exit(ret_val)
First we create a object of the
FactoryProvisioning class passing the arguments
provided to the script. Depending on the Security Mode set in the endpoint_cfg
we can generate a self signed certificate or pass the paths to the certificate for
both the client and server. Next we call
provision_device() that will load the
configuration to the device. Finally we can call
register() to automatically
register the device to the Coiote server. At the end of the script we will try
to catch all exceptions that could show up during script execution. The error
messages should give the user a hint what went wrong in case of any trouble.