3.3. Enabling Secure Communication
Anjay-Lite can be compiled with support for DTLS and linked with the mbedTLS
library. When enabled, the DTLS session is configured from the Resources of the
LwM2M Security
Object (ID /0
).
This article is based on the BC-Security example. The complete code is available in the examples/tutorial/BC-Security directory of the Anjay-Lite repository.
3.3.1. Prerequisites & build flags
To enable secure communication, you need to configure the appropriate build
flags. These can be set either in the CMake build system or in a custom
anjay_config.h file. A minimal example demonstrating the required flags can be
found in examples/tutorial/BC-Security/CMakeLists.txt
and it looks like this:
set(ANJ_WITH_MBEDTLS ON)
set(ANJ_WITH_SECURITY ON)
set(ANJ_NET_WITH_DTLS ON)
ANJ_WITH_MBEDTLS
— enable the bundled mbedTLS integration.ANJ_WITH_SECURITY
— compiles-in code handling security features within Anjay-Lite.ANJ_NET_WITH_DTLS
— enable DTLS transport support.
Note
For more information about these flags, see the anjay_config.h.in
file.
3.3.2. Anjay-Lite with Default mbedTLS Support
The build process of this example targets Linux platforms. For custom embedded
builds, we recommend creating a separate CMakeLists.txt
file that adds all
source files for both Anjay-Lite and mbedTLS, similarly to what is presented in
Compile Client Applications.
By providing the ANJ_WITH_MBEDTLS
flag, two things happen:
Anjay-Lite’s CMake fetches the mbedTLS library and compiles it as part of the build.
Anjay-Lite compiles with the bundled mbedTLS compatibility layer (
src/anj/compat/posix/anj_mbedtls_dtls_socket.c
).
The anj_mbedtls_dtls_socket.c
compatibility layer depends on the
bundled POSIX UDP socket layer. Therefore, the ANJ_WITH_UDP
option
(enabled by default) must remain enabled. For custom embedded platforms, you may
need to implement your own UDP socket compatibility layer.
Important
Anjay-Lite supports mbedTLS version 3.6.4 and newer.
Note
When building for Linux with the CMake files shipped with Anjay-Lite,
you can set your own MBEDTLS_VERSION
or MBEDTLS_ROOT_DIR
.
See cmake/anjay_lite_mbedtls.cmake
for details.
3.3.3. Supported Security Modes
The security mode is determined based on the Security Mode Resource in a given
instance of the Security Object (/0/*/2
). Supported values are:
0
- Pre-Shared Key (PSK) mode — DTLS with PSK is used. Communication is symmetrically encrypted and authenticated using the same secret key, shared between the server and the client.The TLS-PSK identity is stored in the Public Key or Identity Resource (
/0/*/3
). It is a string identifying the key being used, so that the server can uniquely determine which key to use for communication. This string shall be directly stored in this Resource.The Secret Key (
/0/*/5
) Resource shall contain the secret pre-shared key itself, in an opaque binary format appropriate for the cipher suite used by the server.
3
- NoSec mode — In this mode, encryption and authentication are disabled completely and the CoAP messages are transmitted in plain text over the network. It must not be used in production environments, unless end-to-end security is provided at a lower layer (e.g. IPsec). It may be useful for development, testing, and debugging.
The Raw Public Key, Certificate, and Certificate with EST modes described in the LwM2M specification are not currently supported.
In this tutorial, we will focus on enabling security using the PSK mode.
3.3.4. Provisioning Security Configuration
According to the LwM2M specification, the aforementioned Resources shall be provisioned during the Bootstrap Phase. However, if Bootstrap from Smartcard is not used, the Client must contain some factory defaults for connecting to a LwM2M Server or a LwM2M Bootstrap Server. In this section, we will learn how to implement such factory defaults for a DTLS connection.
3.3.4.1. Configuring Encryption Keys
PSK mode requires an Identity and a Pre-Shared Key in the Security Object. In
Anjay-Lite they are set via public_key_or_identity
and secret_key
fields
of anj_dm_security_instance_init_t
.
3.3.4.2. Code Changes
Continuing the previous tutorial, we can modify the security_inst
initialization code:
// Installs Security Object and adds an instance of it.
// An instance of Security Object provides information needed to connect to
// LwM2M server.
static int install_security_obj(anj_t *anj,
anj_dm_security_obj_t *security_obj) {
static const char PSK_IDENTITY[] = "identity";
static const char PSK_KEY[] = "P4s$w0rd";
anj_dm_security_instance_init_t security_inst = {
.ssid = 1,
.server_uri = "coaps://eu.iot.avsystem.cloud:5684",
.security_mode = ANJ_DM_SECURITY_PSK,
.public_key_or_identity = {
.source = ANJ_CRYPTO_DATA_SOURCE_BUFFER,
.info.buffer.data = PSK_IDENTITY,
.info.buffer.data_size = strlen(PSK_IDENTITY)
},
.secret_key = {
.source = ANJ_CRYPTO_DATA_SOURCE_BUFFER,
.info.buffer.data = PSK_KEY,
.info.buffer.data_size = strlen(PSK_KEY)
}
};
anj_dm_security_obj_init(security_obj);
if (anj_dm_security_obj_add_instance(security_obj, &security_inst)
|| anj_dm_security_obj_install(anj, security_obj)) {
return -1;
}
return 0;
}
Note
Notice that the server_uri
field has changed to use the coaps
URI
scheme and port 5684
(the default for secure CoAP).
All remaining activities related to establishing a secure communication channel with the LwM2M Server are performed automatically by Anjay-Lite.
3.3.5. Operational notes
Switching a device from NoSec to PSK while reusing the same endpoint name often requires changes on the server side.
Important
For many LwM2M Servers, including the Coiote IoT Device Management platform, you will need to change the server-side configuration if you previously used NoSec connectivity for the same endpoint name.
The simplest solution might often be to remove the device entry completely and create it from scratch.