1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:12:57 +01:00

Merge pull request #16233 from leandrolanzieri/pr/pkg/wakaama_dtls

pkg/wakaama: add DTLS support
This commit is contained in:
Leandro Lanzieri 2024-05-07 09:19:53 +00:00 committed by GitHub
commit 67f183d6a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 2687 additions and 660 deletions

44
examples/lwm2m/Kconfig Normal file
View File

@ -0,0 +1,44 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menu "Application configuration"
config LWM2M_SERVER_URI
string "LwM2M Server URI to register/bootstrap with"
default "coap://[fd00:dead:beef::1]:5684"
help
The host part of the URI MUST be a valid IPv6 address.
config LWM2M_SERVER_SHORT_ID
int "Server Short ID"
default 1
range 1 65534
choice
bool "Credential type"
menuconfig LWM2M_CRED_PSK
bool "PSK (Pre-shared keys)"
select DTLS_PSK
if LWM2M_CRED_PSK
config LWM2M_PSK_ID
string "PSK Identity"
default "Client_Identity"
config LWM2M_PSK_KEY
string "PSK Key"
default "ThisIsRIOT!"
endif # LWM2M_CRED_PSK
config LWM2M_CRED_RPK
bool "RPK (Raw public keys)"
select DTLS_ECC
endchoice
endmenu # Application configuration

View File

@ -1,5 +1,5 @@
# name of your application # name of your application
APPLICATION = wakaama APPLICATION = lwm2m
# If no BOARD is found in the environment, use this default: # If no BOARD is found in the environment, use this default:
BOARD ?= native BOARD ?= native
@ -7,8 +7,6 @@ BOARD ?= native
# This has to be the absolute path to the RIOT base directory: # This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../.. RIOTBASE ?= $(CURDIR)/../..
# Include packages that pull up and auto-init the link layer. # Include packages that pull up and auto-init the link layer.
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present # NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
USEMODULE += netdev_default USEMODULE += netdev_default
@ -27,21 +25,34 @@ USEMODULE += ps
# development process: # development process:
DEVELHELP ?= 1 DEVELHELP ?= 1
# Specific the server URI address (NOTE: Domain names not supported yet)
SERVER_URI ?= '"coap://[fd00:dead:beef::1]"'
# NOTE: Add the package for wakaama # NOTE: Add the package for wakaama
USEPKG += wakaama USEPKG += wakaama
USEMODULE += wakaama_objects_light_control USEMODULE += wakaama_objects_light_control
# Uncomment to enable Wakaama debug log
#CFLAGS += -DCONFIG_LWM2M_WITH_LOGS=1
# Uncomment to indicate that the server is a LwM2M bootstrap server # add DTLS support
# CFLAGS += -DCONFIG_LWM2M_BOOTSTRAP=1 USEMODULE += wakaama_client_dtls
# Specify sock DTLS implementation
USEPKG += tinydtls
# tinydtls needs crypto secure PRNG
USEMODULE += prng_sha1prng
## Application-specific Configuration options
LWM2M_SERVER_URI ?= '"coap://[fd00:dead:beef::1]:5684"'
LWM2M_SERVER_SHORT_ID ?= 1
CFLAGS += -DEVENT_THREAD_MEDIUM_STACKSIZE='(3*1024)'
include $(RIOTBASE)/Makefile.include include $(RIOTBASE)/Makefile.include
# Configure server via CFLAGS only if not done via Kconfig DTLS_MAX_BUF=1024
# Configure via CFLAGS only if not done via Kconfig
ifndef CONFIG_LWM2M_SERVER_URI ifndef CONFIG_LWM2M_SERVER_URI
CFLAGS += -DCONFIG_LWM2M_SERVER_URI=$(SERVER_URI) CFLAGS += -DCONFIG_LWM2M_SERVER_URI=$(LWM2M_SERVER_URI)
CFLAGS += -DCONFIG_LWM2M_SERVER_SHORT_ID=$(LWM2M_SERVER_SHORT_ID)
CFLAGS += -DCONFIG_DTLS_PEER_MAX=2
CFLAGS += -DCONFIG_MAX_BUF=1024
# Uncomment to enable Wakaama debug log
#CFLAGS += -DCONFIG_LWM2M_WITH_LOGS=1
endif endif

View File

@ -1,5 +1,6 @@
BOARD_INSUFFICIENT_MEMORY := \ BOARD_INSUFFICIENT_MEMORY := \
airfy-beacon \ airfy-beacon \
arduino-mkr1000 \
b-l072z-lrwan1 \ b-l072z-lrwan1 \
blackpill-stm32f103c8 \ blackpill-stm32f103c8 \
blackpill-stm32f103cb \ blackpill-stm32f103cb \
@ -7,8 +8,13 @@ BOARD_INSUFFICIENT_MEMORY := \
bluepill-stm32f103c8 \ bluepill-stm32f103c8 \
bluepill-stm32f103cb \ bluepill-stm32f103cb \
calliope-mini \ calliope-mini \
cc1350-launchpad \
cc2650-launchpad \ cc2650-launchpad \
cc2650stk \ cc2650stk \
e104-bt5010a-tb \
e104-bt5011a-tb \
feather-m0-wifi \
gd32vf103c-start \
hifive1 \ hifive1 \
hifive1b \ hifive1b \
i-nucleo-lrwan1 \ i-nucleo-lrwan1 \
@ -24,16 +30,23 @@ BOARD_INSUFFICIENT_MEMORY := \
nucleo-f042k6 \ nucleo-f042k6 \
nucleo-f070rb \ nucleo-f070rb \
nucleo-f072rb \ nucleo-f072rb \
nucleo-f103rb \
nucleo-f302r8 \ nucleo-f302r8 \
nucleo-f303k8 \ nucleo-f303k8 \
nucleo-f334r8 \ nucleo-f334r8 \
nucleo-l011k4 \ nucleo-l011k4 \
nucleo-l031k6 \ nucleo-l031k6 \
nucleo-l053r8 \ nucleo-l053r8 \
nucleo-l073rz \
olimexino-stm32 \
opencm904 \ opencm904 \
openmote-b \
samd10-xmini \ samd10-xmini \
saml10-xpro \ saml10-xpro \
saml11-xpro \ saml11-xpro \
seeedstudio-gd32 \
sipeed-longan-nano \
sipeed-longan-nano-tft \
slstk3400a \ slstk3400a \
spark-core \ spark-core \
stk3200 \ stk3200 \

View File

@ -41,12 +41,19 @@ Router, you might want to specify:
java -jar ./leshan-server-demo.jar -lh fd00:dead:beef::1 java -jar ./leshan-server-demo.jar -lh fd00:dead:beef::1
``` ```
In the security section click 'Add Security Information', select the security mode
'Pre-Shared Key', and enter the Client endpoint name and the security information
(Identity and Key).
#### Bootstrap server #### Bootstrap server
LwM2M provides a bootstrapping mechanism to provide the clients with information LwM2M provides a bootstrapping mechanism to provide the clients with information
to register to one or more servers. To test this mechanism both the previous server and a bootstrap server should be running. Eclipse Leshan also provides a bootstrap server demo. to register to one or more servers. To test this mechanism both the previous server and a bootstrap server should be running. Eclipse Leshan also provides a bootstrap server demo.
By default the bootstrap server option is disabled, it can be enabled by defining By default the security instance created in the application assumes that a standard LwM2M Server is
`CONFIG_LWM2M_BOOTSTRAP` as 1 (see the Makefile in this application). used. To indicate that the configuration corresponds to a LwM2M Bootstrap Server, set the
corresponding argument (`is_bootstrap`) to true. Also, bootstrap support needs to be enabled in the
wakaama package configurations. This can be done via `make menuconfig` or by setting the CFLAG
`CONFIG_LWM2M_BOOTSTRAP`.
To run the bootstrap server, make sure that the ports it uses are different To run the bootstrap server, make sure that the ports it uses are different
from the ones of previous server (default are 5683 for CoAP, 5684 for CoAPs, from the ones of previous server (default are 5683 for CoAP, 5684 for CoAPs,
@ -66,34 +73,34 @@ BS_COAPSPORT=5686
BS_WEBPORT=8888 BS_WEBPORT=8888
# run the server # run the server
java -jar ./leshan-bsserver-demo.jar --coapport ${BS_COAPPORT} \ java -jar ./leshan-bsserver-demo.jar --coap-port ${BS_COAPPORT} \
--coapsport ${BS_COAPSPORT} --webport ${BS_WEBPORT} --coaps-port ${BS_COAPSPORT} --web-port ${BS_WEBPORT}
``` ```
To set up the configuration of the node and the server: To set up the configuration of the node and the server:
1. Click the `Add new client bootstrap configuration` button. 1. Click the `Add new client bootstrap configuration` button.
2. Fill in the name of the device, it **should** match the one set in 2. Fill in the name of the device, it **should** match the one set as `CONFIG_LWM2M_DEVICE_NAME`,
`lwm2m.h` as `CONFIG_LWM2M_DEVICE_NAME`. in `objects/device.h`.
3. Using the `LWM2M Server` tab enter the address where the LwM2M server is 3. Using the `LWM2M Server` tab enter the address where the LwM2M server is
listening. For now only `No security` mode can be used. listening. Here you can select `No security` or `Pre-Shared Key` modes.
### Running the client ### Running the client
The address set as `CONFIG_LWM2M_SERVER_URI` (in `lwm2m.h` or via `menuconfig`) The server address is set by the application, during the instantiation of the Security object.
should be reachable from the node, e.g. either running on native with a tap It can be set via `menuconfig` or the environmental variable `LWM2M_SERVER_URI`. It should be
interface or as a mote connected to a reachable from the node, e.g. either running on native with a tap interface or as a mote connected
to a
[border router](https://github.com/RIOT-OS/RIOT/tree/master/examples/gnrc_border_router). [border router](https://github.com/RIOT-OS/RIOT/tree/master/examples/gnrc_border_router).
Also, if a bootstrap server is being used the macro `CONFIG_LWM2M_BOOTSTRAP` should be Also, if a bootstrap server is being used, it should be configured in the application via
defined as 1. `menuconfig` or setting the environmental variable `LWM2M_SERVER_BOOTSTRAP` to 1. This information
is used in the Security object instance.
The server URI for the example is being defined using the variable `SERVER_URI`
in the Makefile, and can be changed when compiling.
#### Configure, compile and run #### Configure, compile and run
The Wakaama package can be configured via Kconfig. Its options are placed The Wakaama package can be configured via Kconfig. Its options are placed
under `Packages > Configure Wakaama LwM2M`. To access the configuration under `Packages > Configure Wakaama LwM2M`. There is also an application-specific configuration
interface you can run: menu. There the Server URI and credentials can be set. To access the configuration interface you
can run:
``` ```
make menuconfig make menuconfig
``` ```

View File

@ -0,0 +1,2 @@
CONFIG_DTLS_PEER_MAX=2
CONFIG_DTLS_HANDSHAKE_BUFSIZE_EXP=9

View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup examples
* @{
*
* @file
* @brief PSK and RPK credentials for the LwM2M example.
*
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
*
* @}
*/
#ifndef CREDENTIALS_H
#define CREDENTIALS_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/**
* @brief Default PSK key ID.
*/
#ifndef CONFIG_LWM2M_PSK_ID
#define CONFIG_LWM2M_PSK_ID "Client_Identity"
#endif
/**
* @brief Default PSK secret.
*/
#ifndef CONFIG_LWM2M_PSK_KEY
#define CONFIG_LWM2M_PSK_KEY "ThisIsRIOT!"
#endif
static const uint8_t psk_id[] = CONFIG_LWM2M_PSK_ID;
static const uint8_t psk_key[] = CONFIG_LWM2M_PSK_KEY;
/* openssl ec -in keys.der -inform DER -pubout -outform DER | xxd -i */
static const uint8_t rpk_pub[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xa0, 0xc3, 0x8e, 0xcb, 0xa1,
0x02, 0xeb, 0x5d, 0x25, 0x96, 0x98, 0xbb, 0x60, 0x8e, 0x28, 0x19, 0x56, 0x06, 0x96, 0x70, 0x15,
0x9b, 0x54, 0xff, 0xd9, 0x60, 0x32, 0xc3, 0x3e, 0x89, 0x08, 0xae, 0x3a, 0x33, 0x2f, 0x54, 0x5f,
0x68, 0xa2, 0xac, 0xd1, 0xb9, 0xdf, 0x2b, 0x79, 0x65, 0x49, 0x3f, 0x1c, 0xae, 0x64, 0x7a, 0x32,
0x02, 0xe4, 0x32, 0x8d, 0x6b, 0x22, 0x67, 0x83, 0x0d, 0x7c, 0xb2
};
/* openssl ec -in keys.der -inform DER -no_public -outform DER | xxd -i */
static const uint8_t rpk_priv[] = {
0x30, 0x31, 0x02, 0x01, 0x01, 0x04, 0x20, 0xf9, 0x00, 0xb7, 0x31, 0xc4, 0xa7, 0x09, 0xcd, 0x90,
0x69, 0xc8, 0xac, 0x60, 0xc4, 0x70, 0x58, 0x12, 0xe9, 0xb8, 0x2e, 0x29, 0x12, 0x3c, 0xd1, 0x74,
0x12, 0xbc, 0xf5, 0x81, 0xe5, 0xb5, 0x04, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
0x03, 0x01, 0x07
};
/* provided by server */
static const uint8_t server_rpk_pub[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x8b, 0xd5, 0x0f, 0x73, 0xe2,
0x1d, 0x8f, 0xa3, 0x04, 0x2c, 0x83, 0xd2, 0x1e, 0x85, 0x57, 0x0e, 0xcd, 0xee, 0xf0, 0xc1, 0x14,
0x9b, 0xeb, 0x05, 0x4f, 0xc9, 0x26, 0x3f, 0xab, 0x6d, 0x43, 0x0b, 0xf8, 0xb9, 0xc9, 0x18, 0x74,
0x6f, 0xa1, 0x89, 0x71, 0x92, 0xb2, 0x8f, 0x2f, 0x2a, 0xf2, 0xa1, 0xde, 0xed, 0xf2, 0x81, 0x8d,
0xe4, 0xc2, 0x76, 0xc3, 0x15, 0xff, 0x70, 0xd4, 0xa5, 0x7d, 0x88,
};
#ifdef __cplusplus
}
#endif
#endif /* CREDENTIALS_H */

View File

@ -21,8 +21,13 @@
#include "lwm2m_client.h" #include "lwm2m_client.h"
#include "lwm2m_client_objects.h" #include "lwm2m_client_objects.h"
#include "lwm2m_platform.h" #include "lwm2m_platform.h"
#include "objects/light_control.h"
#include "objects/common.h" #include "objects/common.h"
#include "objects/device.h"
#include "objects/security.h"
#include "objects/light_control.h"
#include "credentials.h"
#define LED_COLOR "FFFFFF" #define LED_COLOR "FFFFFF"
#define LED_APP_TYPE "LED 0" #define LED_APP_TYPE "LED 0"
@ -58,12 +63,13 @@ void lwm2m_cli_init(void)
lwm2m_client_init(&client_data); lwm2m_client_init(&client_data);
/* add objects that will be registered */ /* add objects that will be registered */
obj_list[0] = lwm2m_client_get_security_object(&client_data); obj_list[0] = lwm2m_object_security_init(&client_data);
obj_list[1] = lwm2m_client_get_server_object(&client_data); obj_list[1] = lwm2m_client_get_server_object(&client_data, CONFIG_LWM2M_SERVER_SHORT_ID);
obj_list[2] = lwm2m_client_get_device_object(&client_data); obj_list[2] = lwm2m_object_device_init(&client_data);
obj_list[3] = lwm2m_object_light_control_init(&client_data); obj_list[3] = lwm2m_object_light_control_init(&client_data);
lwm2m_obj_light_control_args_t args = { /* create light control object instance */
lwm2m_obj_light_control_args_t light_args = {
.cb = _light_cb, .cb = _light_cb,
.cb_arg = NULL, .cb_arg = NULL,
.color = LED_COLOR, .color = LED_COLOR,
@ -72,12 +78,54 @@ void lwm2m_cli_init(void)
.app_type_len = sizeof(LED_APP_TYPE) - 1 .app_type_len = sizeof(LED_APP_TYPE) - 1
}; };
int res = lwm2m_object_light_control_instance_create(&args, 0); int res = lwm2m_object_light_control_instance_create(&light_args, 0);
if (res < 0) { if (res < 0) {
puts("Error instantiating light control"); puts("Error instantiating light control");
} }
/* create security object instance */
lwm2m_obj_security_args_t security_args = {
.server_id = CONFIG_LWM2M_SERVER_SHORT_ID,
.server_uri = CONFIG_LWM2M_SERVER_URI,
.security_mode = LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY,
.pub_key_or_id = rpk_pub,
.pub_key_or_id_len = sizeof(rpk_pub),
.secret_key = rpk_priv,
.secret_key_len = sizeof(rpk_priv),
.server_pub_key = server_rpk_pub,
.server_pub_key_len = sizeof(server_rpk_pub),
.is_bootstrap = false, /* set to true when using Bootstrap server */
.client_hold_off_time = 5,
.bootstrap_account_timeout = 0
};
if (IS_ACTIVE(CONFIG_LWM2M_CRED_PSK)) {
security_args.security_mode = LWM2M_SECURITY_MODE_PRE_SHARED_KEY;
security_args.pub_key_or_id = psk_id;
security_args.pub_key_or_id_len = sizeof(psk_id) - 1;
security_args.secret_key = psk_key;
security_args.secret_key_len = sizeof(psk_key) - 1;
}
else if (IS_ACTIVE(CONFIG_LWM2M_CRED_RPK)) {
security_args.security_mode = LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY;
security_args.pub_key_or_id = rpk_pub;
security_args.pub_key_or_id_len = sizeof(rpk_pub);
security_args.secret_key = rpk_priv;
security_args.secret_key_len = sizeof(rpk_priv);
security_args.server_pub_key = server_rpk_pub;
security_args.server_pub_key_len = sizeof(server_rpk_pub);
}
else {
puts("Error: you must select a credential type");
return;
}
res = lwm2m_object_security_instance_create(&security_args, 1);
if (res < 0) {
puts("Could not instantiate the security object");
return;
}
if (!obj_list[0] || !obj_list[1] || !obj_list[2]) { if (!obj_list[0] || !obj_list[1] || !obj_list[2]) {
puts("Could not create mandatory objects"); puts("Could not create mandatory objects");
} }
@ -119,7 +167,7 @@ int lwm2m_cli_cmd(int argc, char **argv)
if (!strcmp(argv[1], "start")) { if (!strcmp(argv[1], "start")) {
/* run the LwM2M client */ /* run the LwM2M client */
if (!connected && lwm2m_client_run(&client_data, obj_list, OBJ_COUNT)) { if (!connected && lwm2m_client_run(&client_data, obj_list, ARRAY_SIZE(obj_list))) {
connected = 1; connected = 1;
} }
return 0; return 0;

View File

@ -7,19 +7,12 @@
menu "tinydtls" menu "tinydtls"
depends on USEPKG_TINYDTLS depends on USEPKG_TINYDTLS
# TODO change to multiple choice after DTLS application support enabling more than one types of cypher suites
choice
bool "Cipher suite to enable"
default DTLS_PSK
config DTLS_PSK config DTLS_PSK
bool "TLS_PSK_WITH_AES_128_CCM_8" bool "TLS_PSK_WITH_AES_128_CCM_8"
config DTLS_ECC config DTLS_ECC
bool "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8" bool "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"
endchoice
config DTLS_DEBUG config DTLS_DEBUG
bool "Enable debug log" bool "Enable debug log"
help help

View File

@ -1,4 +1,4 @@
# Copyright (c) 2019 HAW Hamburg # Copyright (c) 2021 HAW Hamburg
# #
# This file is subject to the terms and conditions of the GNU Lesser # This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level # General Public License v2.1. See the file LICENSE in the top level
@ -10,96 +10,15 @@ menu "Wakaama LwM2M"
menu "Remote server" menu "Remote server"
config LWM2M_STANDARD_PORT config LWM2M_STANDARD_PORT
string "CoAP default port of the LwM2M server" string "CoAP default port of a LwM2M server"
default "5683" default "5683"
config LWM2M_DTLS_PORT config LWM2M_DTLS_PORT
string "CoAPS default port of the LwM2M server" string "CoAPS default port of a LwM2M server"
default "5684" default "5684"
config LWM2M_SERVER_URI
string "LwM2M server URI to register/bootstrap with"
default "coap://[fd00:dead:beef::1]"
help
The host part of the URI MUST be a valid IPv6 address. Host names can
not be resolved at this time.
config LWM2M_SERVER_ID
int "Numeric ID of the Server URI"
default 10
help
This numeric ID corresponds to the server URI specified in the
previous option.
config LWM2M_BOOTSTRAP
bool "Is a bootstrap server"
help
The specified server is a LwM2M bootstrap server.
endmenu # Remote server endmenu # Remote server
menu "Device"
choice
bool "Device binding and queue mode"
default LWM2M_DEVICE_BINDING_U
config LWM2M_DEVICE_BINDING_U
bool "UDP"
config LWM2M_DEVICE_BINDING_UQ
bool "UDP with Queue mode"
config LWM2M_DEVICE_BINDING_S
bool "SMS"
config LWM2M_DEVICE_BINDING_SQ
bool "SMS with Queue mode"
config LWM2M_DEVICE_BINDING_US
bool "UDP and SMS"
config LWM2M_DEVICE_BINDING_UQS
bool "UDP with Queue mode and SMS"
endchoice
config LWM2M_DEVICE_NAME
string "Device name"
default "testRIOTDevice"
help
This is the device name used to register at the LwM2M server.
config LWM2M_DEVICE_MANUFACTURER
string "Device manufacturer"
default "A RIOT maker"
config LWM2M_DEVICE_MODEL
string "Device model"
default "$(BOARD)"
config LWM2M_DEVICE_TYPE
string "Device type"
default "RIOT device"
config LWM2M_DEVICE_SERIAL
string "Device serial number"
default "undefined"
config LWM2M_DEVICE_FW_VERSION
string "Device firmware version"
default ""
config LWM2M_DEVICE_HW_VERSION
string "Device hardware version"
default "$(BOARD)"
config LWM2M_DEVICE_SW_VERSION
string "Device software version"
default ""
endmenu # Device
config LWM2M_DEVICE_TTL config LWM2M_DEVICE_TTL
int "Lifetime of the device" int "Lifetime of the device"
default 300 default 300
@ -107,9 +26,13 @@ config LWM2M_DEVICE_TTL
Lifetime of the device on the LwM2M server, expressed in seconds. Lifetime of the device on the LwM2M server, expressed in seconds.
config LWM2M_LOCAL_PORT config LWM2M_LOCAL_PORT
string "Default port for the local LwM2M instance" string "Port for the local LwM2M CoAP"
default "5683" default "5683"
config LWM2M_LOCAL_DTLS_PORT
string "Port for the local LwM2M CoAPs server"
default "5684"
config LWM2M_ALT_PATH config LWM2M_ALT_PATH
string "Alternate path to place LwM2M resources" string "Alternate path to place LwM2M resources"
default "/" default "/"
@ -121,6 +44,22 @@ config LWM2M_TLSF_BUFFER
int "Allocation buffer size" int "Allocation buffer size"
default 5120 default 5120
config LWM2M_CREDMAN_TAG_BASE
int "Credential tag base"
default 10
help
Number to use as base for assigning tags to @ref net_credman
credentials.
config LWM2M_URI_MAX_SIZE
int "Maximum length of an URI allowed"
default 64
config LWM2M_BOOTSTRAP
bool "Bootsrap server support"
help
Say y to support using a bootstrap server to get server information.
rsource "contrib/objects/Kconfig" rsource "contrib/objects/Kconfig"
endmenu # Wakaama LwM2M endmenu # Wakaama LwM2M

View File

@ -8,8 +8,9 @@ USEMODULE += uri_parser
# folder, by adding 'wakaama_objects_<objectName>' modules # folder, by adding 'wakaama_objects_<objectName>' modules
USEMODULE += wakaama_objects USEMODULE += wakaama_objects
# include the 'device' object implementation (mandatory) # include mandatory objects
USEMODULE += wakaama_objects_device USEMODULE += wakaama_objects_device
USEMODULE += wakaama_objects_security
USEMODULE += ztimer USEMODULE += ztimer
USEMODULE += ztimer_sec USEMODULE += ztimer_sec
@ -22,3 +23,13 @@ endif
# wakaama uses Sock UDP (implemented by some stack) # wakaama uses Sock UDP (implemented by some stack)
USEMODULE += sock_udp USEMODULE += sock_udp
USEMODULE += sock_async_event
USEMODULE += sock_util
USEMODULE += event_timeout
USEMODULE += event_thread
USEMODULE += event_thread_medium
ifneq (,$(filter wakaama_client_dtls, $(USEMODULE)))
USEMODULE += sock_dtls
USEMODULE += credman_load
endif

View File

@ -18,3 +18,4 @@ ifneq (,$(or $(CONFIG_LWM2M_WITH_LOGS),$(filter -DCONFIG_LWM2M_WITH_LOGS=1,$(CFL
endif endif
PSEUDOMODULES += wakaama PSEUDOMODULES += wakaama
PSEUDOMODULES += wakaama_client_dtls

View File

@ -21,9 +21,17 @@
#include <string.h> #include <string.h>
#include "kernel_defines.h"
#include "timex.h" #include "timex.h"
#include "liblwm2m.h" #include "liblwm2m.h"
#include "uri_parser.h"
#include "event/timeout.h"
#include "event/thread.h"
#include "net/sock/async/event.h"
#include "net/sock/util.h"
#include "objects/common.h"
#include "objects/security.h"
#include "objects/device.h"
#include "lwm2m_platform.h" #include "lwm2m_platform.h"
#include "lwm2m_client.h" #include "lwm2m_client.h"
@ -34,26 +42,146 @@
#include "debug.h" #include "debug.h"
/** /**
* @brief Determines if there has been a reboot request on the device object * @brief Callback for event timeout that performs a step on the LwM2M FSM.
*
* @note This function is implemented in object_device.c
*
* @return true Reboot has been requested
* @return false Reboot has not been requested
*/ */
bool lwm2m_device_reboot_requested(void); static void _lwm2m_step_cb(event_t *arg);
/** /**
* @brief Thread with the main loop for receiving packets and stepping the LwM2M * @brief Callback to handle UDP sock events.
* FSM.
*
* @param arg ignored
*/ */
static void *_lwm2m_client_run(void *arg); static void _udp_event_handler(sock_udp_t *sock, sock_async_flags_t type, void *arg);
static char _lwm2m_client_stack[THREAD_STACKSIZE_MAIN + /**
THREAD_EXTRA_STACKSIZE_PRINTF]; * @brief Handle an incoming packet from a remote peer.
static lwm2m_client_data_t *_client_data; */
static void _handle_packet_from_remote(const sock_udp_ep_t *remote,
lwm2m_client_connection_type_t type, uint8_t *buffer,
size_t len);
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
/**
* @brief Callback to handle DTLS sock events.
*/
static void _dtls_event_handler(sock_dtls_t *sock, sock_async_flags_t type, void *arg);
/**
* @brief Try to find a server credential given an UDP endpoint.
*
* @param[in] ep UDP endpoint to match
* @param[in] security_mode Security mode of the instance to find
*
* @return Tag of the credential to use when a suitable one is found
* @retval CREDMAN_TAG_EMPTY otherwise
*/
static credman_tag_t _get_credential(const sock_udp_ep_t *ep, uint8_t security_mode);
#endif
static event_t _lwm2m_step_event = { .handler = _lwm2m_step_cb };
static event_timeout_t _lwm2m_step_event_timeout;
static lwm2m_client_data_t *_client_data = NULL;
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
/**
* @brief Callback registered to the client DTLS sock to select a PSK credential to use.
*/
static credman_tag_t _client_psk_cb(sock_dtls_t *sock, sock_udp_ep_t *ep, credman_tag_t tags[],
unsigned tags_len, const char *hint, size_t hint_len)
{
(void) sock;
(void) tags;
(void) tags_len;
(void) hint;
(void) hint_len;
DEBUG("[lwm2m:client:PSK] getting credential\n");
return _get_credential(ep, LWM2M_SECURITY_MODE_PRE_SHARED_KEY);
}
static credman_tag_t _client_rpk_cb(sock_dtls_t *sock, sock_udp_ep_t *ep, credman_tag_t tags[],
unsigned tags_len)
{
(void) sock;
(void) tags;
(void) tags_len;
DEBUG("[lwm2m:client:RPK] getting credential\n");
return _get_credential(ep, LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY);
}
static credman_tag_t _get_credential(const sock_udp_ep_t *ep, uint8_t security_mode)
{
lwm2m_object_t *sec = lwm2m_get_object_by_id(_client_data, LWM2M_SECURITY_OBJECT_ID);
if (!sec) {
DEBUG("[lwm2m:client] no security object found\n");
return CREDMAN_TAG_EMPTY;
}
/* prepare query */
lwm2m_uri_t query_uri = {
.objectId = LWM2M_SECURITY_OBJECT_ID,
// .resourceId = LWM2M_SECURITY_URI_ID,
.flag = LWM2M_URI_FLAG_OBJECT_ID | LWM2M_URI_FLAG_INSTANCE_ID | LWM2M_URI_FLAG_RESOURCE_ID
};
lwm2m_list_t *instance = sec->instanceList;
/* check all registered security object instances */
while (instance) {
query_uri.instanceId = instance->id;
/* first check the security mode */
query_uri.resourceId = LWM2M_SECURITY_SECURITY_ID;
int64_t mode;
int res = lwm2m_get_int(_client_data, &query_uri, &mode);
if (res < 0) {
DEBUG("[lwm2m:client] could not get security mode of %" PRIu16 "\n", instance->id);
goto check_next;
}
if (mode != security_mode) {
goto check_next;
}
/* if security mode matches, check the URI */
char uri[CONFIG_LWM2M_URI_MAX_SIZE] = { 0 };
size_t uri_len = sizeof(uri);
res = lwm2m_get_string(_client_data, &query_uri, uri, &uri_len);
if (res < 0) {
DEBUG("[lwm2m:client] could not get URI of %" PRIu16 "\n", instance->id);
goto check_next;
}
sock_udp_ep_t inst_ep;
uri_parser_result_t parsed_uri;
res = uri_parser_process_string(&parsed_uri, uri);
if (res < 0) {
DEBUG("[lwm2m:client] could not parse URI\n");
goto check_next;
}
res = sock_udp_str2ep(&inst_ep, parsed_uri.host);
if (res < 0) {
DEBUG("[lwm2m:client] could not convert URI to EP (%s)\n", parsed_uri.host);
goto check_next;
}
if (sock_udp_ep_equal(ep, &inst_ep)) {
credman_tag_t tag = lwm2m_object_security_get_credential(instance->id);
DEBUG("[lwm2m:client:PSK] found matching EP on instance %" PRIu16 "\n", instance->id);
DEBUG("[lwm2m:client:PSK] tag: %" PRIu16 "\n", tag);
return tag;
}
check_next:
instance = instance->next;
}
return CREDMAN_TAG_EMPTY;
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
void lwm2m_client_init(lwm2m_client_data_t *client_data) void lwm2m_client_init(lwm2m_client_data_t *client_data)
{ {
@ -73,11 +201,36 @@ lwm2m_context_t *lwm2m_client_run(lwm2m_client_data_t *client_data,
/* create sock for UDP server */ /* create sock for UDP server */
_client_data->local_ep.port = atoi(CONFIG_LWM2M_LOCAL_PORT); _client_data->local_ep.port = atoi(CONFIG_LWM2M_LOCAL_PORT);
if (sock_udp_create(&_client_data->sock, &_client_data->local_ep, NULL, 0)) { if (sock_udp_create(&_client_data->sock, &_client_data->local_ep, NULL, 0) < 0) {
DEBUG("[lwm2m_client_run] Can't create server socket\n"); DEBUG("[lwm2m_client_run] Can't create server socket\n");
return NULL; return NULL;
} }
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
/* create sock for DTLS server */
_client_data->dtls_local_ep.family = AF_INET6;
_client_data->dtls_local_ep.netif = SOCK_ADDR_ANY_NETIF;
_client_data->dtls_local_ep.port = atoi(CONFIG_LWM2M_LOCAL_DTLS_PORT);
res = sock_udp_create(&_client_data->dtls_udp_sock, &_client_data->dtls_local_ep, NULL, 0);
if (res < 0) {
DEBUG("[lwm2m_client_run] Can't create DTLS server UDP sock\n");
return NULL;
}
res = sock_dtls_create(&_client_data->dtls_sock, &_client_data->dtls_udp_sock,
CREDMAN_TAG_EMPTY, SOCK_DTLS_1_2, SOCK_DTLS_CLIENT);
if (res < 0) {
DEBUG("[lwm2m_client_run] Can't create DTLS server sock\n");
sock_udp_close(&_client_data->dtls_udp_sock);
sock_udp_close(&_client_data->sock);
return NULL;
}
/* register callback for credential selection */
sock_dtls_set_client_psk_cb(&_client_data->dtls_sock, _client_psk_cb);
sock_dtls_set_rpk_cb(&_client_data->dtls_sock, _client_rpk_cb);
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
/* initiate LwM2M */ /* initiate LwM2M */
_client_data->lwm2m_ctx = lwm2m_init(_client_data); _client_data->lwm2m_ctx = lwm2m_init(_client_data);
if (!_client_data->lwm2m_ctx) { if (!_client_data->lwm2m_ctx) {
@ -92,115 +245,200 @@ lwm2m_context_t *lwm2m_client_run(lwm2m_client_data_t *client_data,
return NULL; return NULL;
} }
_client_data->pid = thread_create(_lwm2m_client_stack, #if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
sizeof(_lwm2m_client_stack), lwm2m_client_refresh_dtls_credentials();
THREAD_PRIORITY_MAIN - 1, #endif
THREAD_CREATE_STACKTEST,
_lwm2m_client_run, sock_udp_event_init(&_client_data->sock, EVENT_PRIO_MEDIUM, _udp_event_handler, NULL);
NULL,
"LwM2M client"); #if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
sock_dtls_event_init(&_client_data->dtls_sock, EVENT_PRIO_MEDIUM, _dtls_event_handler, NULL);
#endif
/* periodic event to tick the wakaama state machine */
event_timeout_init(&_lwm2m_step_event_timeout, EVENT_PRIO_MEDIUM, &_lwm2m_step_event);
event_timeout_set(&_lwm2m_step_event_timeout, LWM2M_CLIENT_MIN_REFRESH_TIME);
return _client_data->lwm2m_ctx; return _client_data->lwm2m_ctx;
} }
static void *_lwm2m_client_run(void *arg) static void _handle_packet_from_remote(const sock_udp_ep_t *remote,
lwm2m_client_connection_type_t type, uint8_t *buffer,
size_t len)
{ {
(void) arg; lwm2m_client_connection_t *conn;
time_t reboot_time = 0;
while (1) {
time_t tv = LWM2M_CLIENT_MIN_REFRESH_TIME;
uint8_t rcv_buf[LWM2M_CLIENT_RCV_BUFFER_SIZE];
ssize_t rcv_len = sizeof(rcv_buf);
sock_udp_ep_t remote;
if (lwm2m_device_reboot_requested()) { DEBUG("[lwm2m:client] finding connection\n");
time_t tv_sec; conn = lwm2m_client_connection_find(_client_data->conn_list, remote, type);
tv_sec = lwm2m_gettime(); if (conn) {
DEBUG("[lwm2m:client] handle packet (%i bytes)\n", (int)len);
if (0 == reboot_time) { int result = lwm2m_connection_handle_packet(conn, buffer, len, _client_data);
DEBUG("reboot requested; rebooting in %u seconds\n", if (0 != result) {
LWM2M_CLIENT_REBOOT_TIME); DEBUG("[lwm2m:client] error handling message %i\n", result);
reboot_time = tv_sec + LWM2M_CLIENT_REBOOT_TIME;
}
if (reboot_time < tv_sec) {
DEBUG("reboot time expired, rebooting ...\n");
pm_reboot();
}
else {
tv = reboot_time - tv_sec;
}
}
/*
* This function does two things:
* - first it does the work needed by liblwm2m (eg. (re)sending some
* packets).
* - Secondly it adjusts the timeout value (default 60s) depending on the
* state of the transaction
* (eg. retransmission) and the time between the next operation
*/
lwm2m_step(_client_data->lwm2m_ctx, &tv);
DEBUG(" -> State: ");
switch (_client_data->lwm2m_ctx->state) {
case STATE_INITIAL:
DEBUG("STATE_INITIAL\n");
break;
case STATE_BOOTSTRAP_REQUIRED:
DEBUG("STATE_BOOTSTRAP_REQUIRED\n");
break;
case STATE_BOOTSTRAPPING:
DEBUG("STATE_BOOTSTRAPPING\n");
break;
case STATE_REGISTER_REQUIRED:
DEBUG("STATE_REGISTER_REQUIRED\n");
break;
case STATE_REGISTERING:
DEBUG("STATE_REGISTERING\n");
break;
case STATE_READY:
DEBUG("STATE_READY\n");
if (tv > LWM2M_CLIENT_MIN_REFRESH_TIME) {
tv = LWM2M_CLIENT_MIN_REFRESH_TIME;
}
break;
default:
DEBUG("Unknown...\n");
break;
}
sock_udp_ep_t local;
int res = sock_udp_get_local(&_client_data->sock, &local);
/* avoid compilation errors if NDEBUG is enabled */
(void)res;
assert(res >= 0);
DEBUG("Waiting for UDP packet on port: %d\n", local.port);
rcv_len = sock_udp_recv(&_client_data->sock, rcv_buf, sizeof(rcv_buf),
tv * US_PER_SEC, &remote);
DEBUG("sock_udp_recv()\n");
if (rcv_len > 0) {
DEBUG("Finding connection\n");
lwm2m_client_connection_t *conn = lwm2m_client_connection_find(
_client_data->conn_list, &remote);
if (conn) {
DEBUG("lwm2m_connection_handle_packet(%" PRIiSIZE ")\n", rcv_len);
int result = lwm2m_connection_handle_packet(conn, rcv_buf,
rcv_len,
_client_data);
if (0 != result) {
DEBUG("error handling message %i\n", result);
}
}
else {
DEBUG("Could not find incoming connection\n");
}
}
else if ((rcv_len < 0) &&
((rcv_len != -EAGAIN) && (rcv_len != -ETIMEDOUT))) {
DEBUG("Unexpected sock_udp_recv error code %" PRIiSIZE "\n", rcv_len);
}
else {
DEBUG("UDP error code: %" PRIiSIZE "\n", rcv_len);
} }
} }
return NULL; else {
DEBUG("[lwm2m:client] couldn't find incoming connection\n");
}
} }
static void _udp_event_handler(sock_udp_t *sock, sock_async_flags_t type, void *arg)
{
(void) arg;
sock_udp_ep_t remote;
if (type & SOCK_ASYNC_MSG_RECV) {
uint8_t rcv_buf[LWM2M_CLIENT_RCV_BUFFER_SIZE];
ssize_t rcv_len = sock_udp_recv(sock, rcv_buf, sizeof(rcv_buf), 0, &remote);
if (rcv_len <= 0) {
DEBUG("[lwm2m:client] UDP receive failure: %i\n", (int)rcv_len);
return;
}
_handle_packet_from_remote(&remote, LWM2M_CLIENT_CONN_UDP, rcv_buf, rcv_len);
}
}
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
static void _dtls_event_handler(sock_dtls_t *sock, sock_async_flags_t type, void *arg)
{
(void) arg;
sock_udp_ep_t remote;
sock_dtls_session_t dtls_remote;
uint8_t rcv_buf[LWM2M_CLIENT_RCV_BUFFER_SIZE];
if (type & SOCK_ASYNC_MSG_RECV) {
ssize_t rcv_len = sock_dtls_recv(sock, &dtls_remote, rcv_buf, sizeof(rcv_buf), 0);
if (rcv_len <= 0) {
DEBUG("[lwm2m:client] DTLS receive failure: %i\n", (int)rcv_len);
return;
}
sock_dtls_session_get_udp_ep(&dtls_remote, &remote);
_handle_packet_from_remote(&remote, LWM2M_CLIENT_CONN_DTLS, rcv_buf, rcv_len);
}
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
static void _lwm2m_step_cb(event_t *arg)
{
(void) arg;
time_t next_step = LWM2M_CLIENT_MIN_REFRESH_TIME;
/* check if we need to reboot */
if (lwm2m_device_reboot_requested()) {
DEBUG("[lwm2m:client] reboot requested, rebooting ...\n");
pm_reboot();
}
/* perform step on the LwM2M FSM */
lwm2m_step(_client_data->lwm2m_ctx, &next_step);
DEBUG("[lwm2m:client] state: ");
switch (_client_data->lwm2m_ctx->state) {
case STATE_INITIAL:
DEBUG("STATE_INITIAL\n");
break;
case STATE_BOOTSTRAP_REQUIRED:
DEBUG("STATE_BOOTSTRAP_REQUIRED\n");
break;
case STATE_BOOTSTRAPPING:
DEBUG("STATE_BOOTSTRAPPING\n");
break;
case STATE_REGISTER_REQUIRED:
DEBUG("STATE_REGISTER_REQUIRED\n");
break;
case STATE_REGISTERING:
DEBUG("STATE_REGISTERING\n");
break;
case STATE_READY:
DEBUG("STATE_READY\n");
if (next_step > LWM2M_CLIENT_MIN_REFRESH_TIME) {
next_step = LWM2M_CLIENT_MIN_REFRESH_TIME;
}
break;
default:
DEBUG("Unknown...\n");
break;
}
/* program next step */
event_timeout_set(&_lwm2m_step_event_timeout, next_step * US_PER_SEC);
}
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
void lwm2m_client_add_credential(credman_tag_t tag)
{
if (!_client_data) {
return;
}
const credman_tag_t *creds;
size_t creds_len = sock_dtls_get_credentials(&_client_data->dtls_sock, &creds);
DEBUG("[lwm2m:client] trying to add credential with tag %" PRIu16 "\n", tag);
for (unsigned i = 0; i < creds_len; i++) {
if (creds[i] == tag) {
return;
}
}
sock_dtls_add_credential(&_client_data->dtls_sock, tag);
DEBUG("[lwm2m:client] added\n");
}
void lwm2m_client_remove_credential(credman_tag_t tag)
{
DEBUG("[lwm2m:client] removing credential with tag %" PRIu16 "\n", tag);
sock_dtls_remove_credential(&_client_data->dtls_sock, tag);
}
void lwm2m_client_refresh_dtls_credentials(void)
{
if (!_client_data) {
return;
}
DEBUG("[lwm2m:client:refresh_cred] refreshing DTLS credentials\n");
lwm2m_object_t *sec = lwm2m_get_object_by_id(_client_data, LWM2M_SECURITY_OBJECT_ID);
if (!sec) {
DEBUG("[lwm2m:client:refresh_cred] no security object found\n");
return;
}
/* prepare query */
lwm2m_uri_t query_uri = {
.objectId = LWM2M_SECURITY_OBJECT_ID,
.flag = LWM2M_URI_FLAG_OBJECT_ID | LWM2M_URI_FLAG_INSTANCE_ID | LWM2M_URI_FLAG_RESOURCE_ID
};
lwm2m_list_t *instance = sec->instanceList;
int64_t val;
/* check all registered security object instances */
do {
/* get the security mode */
query_uri.instanceId = instance->id;
query_uri.resourceId = LWM2M_SECURITY_SECURITY_ID;
int res = lwm2m_get_int(_client_data, &query_uri, &val);
if (res < 0) {
DEBUG("[lwm2m:client:refresh_cred] could not get security mode of %" PRIu16 "\n",
instance->id);
continue;
}
if (val == LWM2M_SECURITY_MODE_PRE_SHARED_KEY ||
val == LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY) {
credman_tag_t tag = lwm2m_object_security_get_credential(instance->id);
if (tag != CREDMAN_TAG_EMPTY) {
lwm2m_client_add_credential(tag);
}
}
} while ((instance = instance->next) != NULL);
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */

View File

@ -39,11 +39,18 @@
*/ */
#include <stddef.h> #include <stddef.h>
#include <inttypes.h>
#include "kernel_defines.h" #include "kernel_defines.h"
#include "net/netif.h" #include "net/netif.h"
#include "uri_parser.h" #include "uri_parser.h"
#include "liblwm2m.h" #include "liblwm2m.h"
#include "net/sock/udp.h"
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
#include "net/sock/dtls.h"
#endif
#include "lwm2m_client.h" #include "lwm2m_client.h"
#include "lwm2m_client_config.h" #include "lwm2m_client_config.h"
#include "lwm2m_client_connection.h" #include "lwm2m_client_connection.h"
@ -88,7 +95,7 @@ static int _connection_send(lwm2m_client_connection_t *conn, uint8_t *buffer,
* @param[in] iface_len interface string length * @param[in] iface_len interface string length
* *
* @return pointer to the interface to use on success * @return pointer to the interface to use on success
* @return NULL on error * @retval NULL on error
*/ */
static netif_t *_get_interface(const char *iface, size_t len); static netif_t *_get_interface(const char *iface, size_t len);
@ -97,7 +104,7 @@ void *lwm2m_connect_server(uint16_t sec_obj_inst_id, void *user_data)
lwm2m_client_data_t *client_data = (lwm2m_client_data_t *)user_data; lwm2m_client_data_t *client_data = (lwm2m_client_data_t *)user_data;
lwm2m_client_connection_t *new_conn; lwm2m_client_connection_t *new_conn;
DEBUG("[lwm2m_connect_server] Connecting to server in security instance %d\n", sec_obj_inst_id); DEBUG("[lwm2m_connect_server] Connecting to server in security instance %" PRIu16 "\n", sec_obj_inst_id);
new_conn = _connection_create(sec_obj_inst_id, client_data); new_conn = _connection_create(sec_obj_inst_id, client_data);
if (new_conn) { if (new_conn) {
@ -170,9 +177,9 @@ uint8_t lwm2m_buffer_send(void *sessionH, uint8_t *buffer, size_t length,
return COAP_NO_ERROR; return COAP_NO_ERROR;
} }
lwm2m_client_connection_t *lwm2m_client_connection_find( lwm2m_client_connection_t *lwm2m_client_connection_find(lwm2m_client_connection_t *conn_list,
lwm2m_client_connection_t *conn_list, const sock_udp_ep_t *remote,
const sock_udp_ep_t *remote) lwm2m_client_connection_type_t type)
{ {
lwm2m_client_connection_t *conn = conn_list; lwm2m_client_connection_t *conn = conn_list;
@ -180,7 +187,7 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
uint8_t ip_len = 128; uint8_t ip_len = 128;
ipv6_addr_to_str(ip, (ipv6_addr_t *)&remote->addr.ipv6, ip_len); ipv6_addr_to_str(ip, (ipv6_addr_t *)&remote->addr.ipv6, ip_len);
DEBUG("Looking for connection from [%s]:%d\n", ip, remote->port); DEBUG("Looking for connection from [%s]:%" PRIu16 "\n", ip, remote->port);
if (conn_list == NULL) { if (conn_list == NULL) {
DEBUG("Conn list is null!"); DEBUG("Conn list is null!");
@ -188,8 +195,8 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
while (conn != NULL) { while (conn != NULL) {
ipv6_addr_to_str(ip, (ipv6_addr_t *)&conn->remote.addr.ipv6, ip_len); ipv6_addr_to_str(ip, (ipv6_addr_t *)&conn->remote.addr.ipv6, ip_len);
DEBUG("Comparing to [%s]:%d\n", ip, conn->remote.port); DEBUG("Comparing to [%s]:%" PRIu16 "\n", ip, conn->remote.port);
if ((conn->remote.port == remote->port) && if ((conn->remote.port == remote->port) && conn->type == type &&
ipv6_addr_equal((ipv6_addr_t *)&(conn->remote.addr.ipv6), ipv6_addr_equal((ipv6_addr_t *)&(conn->remote.addr.ipv6),
(ipv6_addr_t *)&(remote->addr.ipv6))) { (ipv6_addr_t *)&(remote->addr.ipv6))) {
break; break;
@ -199,9 +206,8 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
return conn; return conn;
} }
int lwm2m_connection_handle_packet(lwm2m_client_connection_t *conn, int lwm2m_connection_handle_packet(lwm2m_client_connection_t *conn, uint8_t *buffer,
uint8_t *buffer, size_t num_bytes, size_t num_bytes, lwm2m_client_data_t *client_data)
lwm2m_client_data_t *client_data)
{ {
lwm2m_handle_packet(client_data->lwm2m_ctx, buffer, num_bytes, conn); lwm2m_handle_packet(client_data->lwm2m_ctx, buffer, num_bytes, conn);
return 0; return 0;
@ -211,12 +217,26 @@ static int _connection_send(lwm2m_client_connection_t *conn, uint8_t *buffer,
size_t buffer_size, size_t buffer_size,
lwm2m_client_data_t *client_data) lwm2m_client_data_t *client_data)
{ {
ssize_t sent_bytes = sock_udp_send(&(client_data->sock), buffer, DEBUG("[_connection_send] trying to send %" PRIiSIZE " bytes\n", buffer_size);
buffer_size, &(conn->remote)); if (conn->type == LWM2M_CLIENT_CONN_UDP) {
if (sent_bytes <= 0) { ssize_t sent_bytes = sock_udp_send(&(client_data->sock), buffer,
DEBUG("[_connection_send] Could not send UDP packet: %" PRIiSIZE "\n", sent_bytes); buffer_size, &(conn->remote));
return -1; if (sent_bytes <= 0) {
DEBUG("[_connection_send] Could not send UDP packet: %i\n", (int)sent_bytes);
return -1;
}
} }
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
else {
ssize_t sent_bytes = sock_dtls_send(&client_data->dtls_sock, &conn->session, buffer,
buffer_size, SOCK_NO_TIMEOUT);
if (sent_bytes <= 0) {
DEBUG("[_connection_send] Could not send DTLS packet: %i\n", (int)sent_bytes);
return -1;
}
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
conn->last_send = lwm2m_gettime(); conn->last_send = lwm2m_gettime();
return 0; return 0;
} }
@ -225,7 +245,8 @@ static netif_t *_get_interface(const char *iface, size_t iface_len)
{ {
netif_t *netif = NULL; netif_t *netif = NULL;
if (iface == NULL) { if (!iface || !iface_len) {
DEBUG("[lwm2m:client] no interface defined in host\n");
/* get the number of net interfaces */ /* get the number of net interfaces */
unsigned netif_numof = 0; unsigned netif_numof = 0;
while ((netif = netif_iter(netif)) != NULL) { while ((netif = netif_iter(netif)) != NULL) {
@ -240,6 +261,7 @@ static netif_t *_get_interface(const char *iface, size_t iface_len)
} }
} }
else { else {
DEBUG("[lwm2m:client] getting interface by name %.*s\n", (unsigned)iface_len, iface);
netif = netif_get_by_name_buffer(iface, iface_len); netif = netif_get_by_name_buffer(iface, iface_len);
} }
@ -250,7 +272,7 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
lwm2m_client_data_t *client_data) lwm2m_client_data_t *client_data)
{ {
lwm2m_client_connection_t *conn = NULL; lwm2m_client_connection_t *conn = NULL;
char uri[MAX_URI_LENGTH]; char uri[MAX_URI_LENGTH] = { 0 };
size_t uri_len = ARRAY_SIZE(uri); size_t uri_len = ARRAY_SIZE(uri);
uint16_t port; uint16_t port;
bool is_bootstrap; bool is_bootstrap;
@ -299,7 +321,7 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
port = parsed_uri.port; port = parsed_uri.port;
} }
DEBUG("[_connection_create] Creating connection to Host: %.*s, Port: %u\n", DEBUG("[_connection_create] Creating connection to Host: %.*s, Port: %" PRIu16 "\n",
parsed_uri.ipv6addr_len, parsed_uri.ipv6addr, port); parsed_uri.ipv6addr_len, parsed_uri.ipv6addr, port);
/* allocate new connection */ /* allocate new connection */
@ -331,7 +353,9 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
* is only one defined. */ * is only one defined. */
if (ipv6_addr_is_link_local((ipv6_addr_t *)&conn->remote.addr.ipv6)) { if (ipv6_addr_is_link_local((ipv6_addr_t *)&conn->remote.addr.ipv6)) {
netif_t *netif = _get_interface(parsed_uri.zoneid, parsed_uri.zoneid_len); netif_t *netif = _get_interface(parsed_uri.zoneid, parsed_uri.zoneid_len);
if (netif == NULL) { if (netif == NULL) {
DEBUG("[lwm2m:client] could not determine an interface to use\n");
goto free_out; goto free_out;
} }
else { else {
@ -343,6 +367,40 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
} }
} }
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
uint8_t buf[DTLS_HANDSHAKE_BUFSIZE];
int64_t val;
resource_uri.resourceId = LWM2M_SECURITY_SECURITY_ID;
res = lwm2m_get_int(client_data, &resource_uri, &val);
if (res < 0) {
DEBUG("[lwm2m:client] could not get security instance mode\n");
goto free_out;
}
if (val == LWM2M_SECURITY_MODE_PRE_SHARED_KEY || val == LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY) {
conn->type = LWM2M_CLIENT_CONN_DTLS;
DEBUG("[lwm2m:client] DTLS session init\n");
res = sock_dtls_session_init(&client_data->dtls_sock, &conn->remote, &conn->session);
if (res <= 0) {
DEBUG("[lwm2m:client] could not initiate DTLS session\n");
goto free_out;
}
DEBUG("[lwm2m:client] receiving DTLS handshake\n");
res = sock_dtls_recv(&client_data->dtls_sock, &conn->session, buf, sizeof(buf), US_PER_SEC);
if (res != -SOCK_DTLS_HANDSHAKE) {
DEBUG("[lwm2m:client] error creating session: %i\n", res);
goto free_out;
}
DEBUG("[lwm2m:client] connection to server successful\n");
}
else {
conn->type = LWM2M_CLIENT_CONN_UDP;
}
#else
conn->type = LWM2M_CLIENT_CONN_UDP;
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
conn->last_send = lwm2m_gettime(); conn->last_send = lwm2m_gettime();
goto out; goto out;

View File

@ -21,52 +21,24 @@
#include "kernel_defines.h" #include "kernel_defines.h"
#include "lwm2m_client.h" #include "lwm2m_client.h"
#include "objects/device.h"
#include "lwm2m_client_config.h" #include "lwm2m_client_config.h"
#include "lwm2m_client_objects.h" #include "lwm2m_client_objects.h"
/* These functions are defined by the objects (object_security.c and /* These functions are defined by the objects (object_server.c is implemented by
* object_server.c are implemented by the Wakaama package. device.c can be * the Wakaama package. security.c and device.c can be found in
* found in 'contrib/objects') */ * 'contrib/objects') */
lwm2m_object_t *get_security_object(int server_id, const char *server_uri,
char *bs_psk_id, char *psk,
uint16_t psk_len, bool is_bootstrap);
lwm2m_object_t *get_server_object(int server_id, const char *binding, lwm2m_object_t *get_server_object(int server_id, const char *binding,
int lifetime, bool storing); int lifetime, bool storing);
lwm2m_object_t *lwm2m_get_object_device(void);
lwm2m_object_t *lwm2m_client_get_security_object( lwm2m_object_t *lwm2m_client_get_server_object(lwm2m_client_data_t *client_data,
lwm2m_client_data_t *client_data) int server_id)
{ {
(void)client_data; (void)client_data;
lwm2m_object_t *ret; lwm2m_object_t *ret;
char *server_uri = CONFIG_LWM2M_SERVER_URI;
int server_id = CONFIG_LWM2M_SERVER_ID;
uint16_t psk_len = -1;
char *psk_buffer = NULL;
char *psk_id = NULL;
ret = get_security_object(server_id, server_uri, psk_id, psk_buffer,
psk_len, IS_ACTIVE(CONFIG_LWM2M_BOOTSTRAP));
return ret;
}
lwm2m_object_t *lwm2m_client_get_server_object(
lwm2m_client_data_t *client_data)
{
(void)client_data;
lwm2m_object_t *ret;
int server_id = CONFIG_LWM2M_SERVER_ID;
int lifetime = CONFIG_LWM2M_DEVICE_TTL; int lifetime = CONFIG_LWM2M_DEVICE_TTL;
ret = get_server_object(server_id, CONFIG_LWM2M_DEVICE_BINDINGS, lifetime, ret = get_server_object(server_id, CONFIG_LWM2M_DEVICE_BINDINGS, lifetime,
false); false);
return ret; return ret;
} }
lwm2m_object_t *lwm2m_client_get_device_object(
lwm2m_client_data_t *client_data)
{
(void)client_data;
return lwm2m_get_object_device();
}

View File

@ -5,4 +5,6 @@
# directory for more details. # directory for more details.
# #
rsource "Kconfig.device"
rsource "Kconfig.security"
rsource "Kconfig.light_control" rsource "Kconfig.light_control"

View File

@ -0,0 +1,68 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menu "Device"
choice
bool "Device binding and queue mode"
default LWM2M_DEVICE_BINDING_U
config LWM2M_DEVICE_BINDING_U
bool "UDP"
config LWM2M_DEVICE_BINDING_UQ
bool "UDP with Queue mode"
config LWM2M_DEVICE_BINDING_S
bool "SMS"
config LWM2M_DEVICE_BINDING_SQ
bool "SMS with Queue mode"
config LWM2M_DEVICE_BINDING_US
bool "UDP and SMS"
config LWM2M_DEVICE_BINDING_UQS
bool "UDP with Queue mode and SMS"
endchoice
config LWM2M_DEVICE_NAME
string "Device name"
default "testRIOTDevice"
help
This is the device name used to register at the LwM2M server.
config LWM2M_DEVICE_MANUFACTURER
string "Device manufacturer"
default "A RIOT maker"
config LWM2M_DEVICE_MODEL
string "Device model"
default "$(BOARD)"
config LWM2M_DEVICE_TYPE
string "Device type"
default "RIOT device"
config LWM2M_DEVICE_SERIAL
string "Device serial number"
default "undefined"
config LWM2M_DEVICE_FW_VERSION
string "Device firmware version"
default ""
config LWM2M_DEVICE_HW_VERSION
string "Device hardware version"
default "$(BOARD)"
config LWM2M_DEVICE_SW_VERSION
string "Device software version"
default ""
endmenu # Device

View File

@ -0,0 +1,26 @@
# Copyright (c) 2021 HAW Hamburg
#
# This file is subject to the terms and conditions of the GNU Lesser
# General Public License v2.1. See the file LICENSE in the top level
# directory for more details.
#
menu "Security object"
config LWM2M_OBJ_SECURITY_INSTANCES_MAX
int "Maximum number of instances of the Security object"
default 2
config LWM2M_OBJ_SECURITY_PUB_KEY_ID_BUFSIZE
int "Buffer size of the public key or ID resource"
default 128
config LWM2M_OBJ_SECURITY_SERVER_PUB_KEY_BUFSIZE
int "Buffer size of the server public key resource"
default 128
config LWM2M_OBJ_SECURITY_SEC_KEY_BUFSIZE
int "Buffer size of the secret key resource"
default 64
endmenu # Security object

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (C) 2018 Beduino Master Projekt - University of Bremen * Copyright (C) 2018 Beduino Master Projekt - University of Bremen
* 2021 HAW Hamburg
* *
* This file is subject to the terms and conditions of the GNU Lesser * This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level * General Public License v2.1. See the file LICENSE in the top level
@ -13,6 +14,7 @@
* @brief Device object implementation for LwM2M client using Wakaama * @brief Device object implementation for LwM2M client using Wakaama
* *
* @author Christian Manal <manal@uni-bremen.de> * @author Christian Manal <manal@uni-bremen.de>
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @} * @}
*/ */
@ -25,43 +27,90 @@
#include "objects/device.h" #include "objects/device.h"
#include "lwm2m_client_config.h" #include "lwm2m_client_config.h"
#define ENABLE_DEBUG 0
#include "debug.h"
/* Set to true if reboot requested. */ /* Set to true if reboot requested. */
static bool reboot; static bool reboot;
/* Lookup table for static resources of device object */ /**
static const char *_static_resources[] = { * @brief 'Execute' callback for the Device object.
[LWM2M_RES_MANUFACTURER] = CONFIG_LWM2M_DEVICE_MANUFACTURER, *
[LWM2M_RES_MODEL_NO] = CONFIG_LWM2M_DEVICE_MODEL, * @param[in] instance_id Instance ID. Should be 0 as a single instance exists.
[LWM2M_RES_SERIAL] = CONFIG_LWM2M_DEVICE_SERIAL, * @param[in] resource_id ID of the resource to execute.
[LWM2M_RES_FW_VER] = CONFIG_LWM2M_DEVICE_FW_VERSION, * @param[in] buffer Information needed for the execution.
[LWM2M_RES_BINDINGS] = CONFIG_LWM2M_DEVICE_BINDINGS, * @param[in] length Length of @p buffer.
[LWM2M_RES_TYPE] = CONFIG_LWM2M_DEVICE_TYPE, * @param[in] object Device object pointer
[LWM2M_RES_HW_VERSION] = CONFIG_LWM2M_DEVICE_HW_VERSION, *
[LWM2M_RES_SW_VERSION] = CONFIG_LWM2M_DEVICE_SW_VERSION, * @return COAP_204_CHANGED on success
[LWM2M_DEVICE_RESOURCES] = NULL * @return COAP_404_NOT_FOUND when wrong instance specified
* @return COAP_400_BAD_REQUEST when wrong information has been sent
* @return COAP_405_METHOD_NOT_ALLOWED when trying to execute a resource that is not supported
*/
static uint8_t _execute_cb(uint16_t instance_id, uint16_t resource_id, uint8_t *buffer, int length,
lwm2m_object_t *object);
/**
* @brief 'Read' callback for the Device object.
*
* @param[in] instance_id Instance ID. Should be 0 as a single instance exists.
* @param[in, out] num_data Number of resources requested. 0 means all.
* @param[in, out] data_array Initialized data array to output the values,
* when @p num_data != 0. Uninitialized otherwise.
* @param[in] object Device object pointer
*
* @return COAP_205_CONTENT on success
* @return COAP_404_NOT_FOUND when resource can't be found
* @return COAP_500_INTERNAL_SERVER_ERROR otherwise
*/
static uint8_t _read_cb(uint16_t instance_id, int *num_data, lwm2m_data_t **data_array,
lwm2m_object_t *object);
/**
* @brief 'Discover' callback for the Device object.
*
* @param[in] instance_id Instance ID. Should be 0 as a single instance exists.
* @param[in, out] num_data Number of resources requested. 0 means all.
* @param[in, out] data_array Initialized data array to determine if the resource exists,
* when @p num_data != 0. Uninitialized otherwise.
* @param[in] object Device object pointer
*
* @return COAP_205_CONTENT on success
* @return COAP_404_NOT_FOUND when a resource is not supported
* @return COAP_500_INTERNAL_SERVER_ERROR otherwise
*/
static uint8_t _discover_cb(uint16_t instance_id, int *num_data, lwm2m_data_t **data_array,
lwm2m_object_t *object);
typedef struct {
lwm2m_list_t list; /**< Linked list handle */
} lwm2m_obj_device_inst_t;
static const lwm2m_obj_device_inst_t _instance;
/**
* @brief Implementation of the object interface for the Device Object.
*/
static lwm2m_object_t _device_object = {
.next = NULL,
.objID = LWM2M_DEVICE_OBJECT_ID,
.instanceList = (lwm2m_list_t *)&_instance,
.readFunc = _read_cb,
.executeFunc = _execute_cb,
.discoverFunc = _discover_cb,
.writeFunc = NULL,
.deleteFunc = NULL,
.createFunc = NULL,
.userData = NULL
}; };
/*Descriptor of a LwM2M device object instance */ static uint8_t _discover_cb(uint16_t instance_id, int *num_data, lwm2m_data_t **data_array,
typedef struct { lwm2m_object_t *object)
uint8_t *power_sources; /**< types of power sources (0-7) */
uint16_t *power_voltage; /**< voltage of power sources in mV */
uint16_t *power_current; /**< current of power sources in mA */
uint8_t battery_status; /**< battery status (0-6) */
uint32_t mem_total; /**< amount of memory on the device in kB */
uint16_t(*ext_dev_info)[2]; /**< external devices information */
uint8_t ext_dev_info_len; /**< amount of external devices information */
uint8_t error_code[7]; /**< error codes */
uint8_t error_code_used; /**< amount of error codes used */
} dev_data_t;
static uint8_t prv_device_discover(uint16_t instance_id, int *num_dataP,
lwm2m_data_t **data_arrayP,
lwm2m_object_t *objectP)
{ {
uint8_t result; uint8_t result;
int i; int i;
(void)objectP; (void)object;
if (instance_id != 0) { if (instance_id != 0) {
return COAP_404_NOT_FOUND; return COAP_404_NOT_FOUND;
@ -69,7 +118,7 @@ static uint8_t prv_device_discover(uint16_t instance_id, int *num_dataP,
result = COAP_205_CONTENT; result = COAP_205_CONTENT;
if (*num_dataP == 0) { if (*num_data == 0) {
/* This list must contain all available resources */ /* This list must contain all available resources */
uint16_t res[] = { uint16_t res[] = {
LWM2M_RES_MANUFACTURER, LWM2M_RES_MODEL_NO, LWM2M_RES_SERIAL, LWM2M_RES_MANUFACTURER, LWM2M_RES_MODEL_NO, LWM2M_RES_SERIAL,
@ -80,19 +129,22 @@ static uint8_t prv_device_discover(uint16_t instance_id, int *num_dataP,
}; };
int len = ARRAY_SIZE(res); int len = ARRAY_SIZE(res);
*data_arrayP = lwm2m_data_new(len); *data_array = lwm2m_data_new(len);
if (*data_arrayP == NULL) { *num_data = len;
if (*data_array == NULL) {
DEBUG("[lwm2m:device:discover] could not allocate data array\n");
return COAP_500_INTERNAL_SERVER_ERROR; return COAP_500_INTERNAL_SERVER_ERROR;
} }
*num_dataP = len;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
(*data_arrayP)[i].id = res[i]; (*data_array)[i].id = res[i];
} }
} }
else { else {
/* Check if each given resource is present */ /* Check if each given resource is present */
for (i = 0; i < *num_dataP && result == COAP_205_CONTENT; i++) { for (i = 0; i < *num_data && result == COAP_205_CONTENT; i++) {
switch ((*data_arrayP)[i].id) { switch ((*data_array)[i].id) {
case LWM2M_RES_MANUFACTURER: case LWM2M_RES_MANUFACTURER:
case LWM2M_RES_MODEL_NO: case LWM2M_RES_MODEL_NO:
case LWM2M_RES_SERIAL: case LWM2M_RES_SERIAL:
@ -114,23 +166,22 @@ static uint8_t prv_device_discover(uint16_t instance_id, int *num_dataP,
return result; return result;
} }
static uint8_t prv_device_read(uint16_t instance_id, int *num_dataP, static uint8_t _read_cb(uint16_t instance_id, int *num_data, lwm2m_data_t **data_array,
lwm2m_data_t **data_arrayP, lwm2m_object_t *object)
lwm2m_object_t *objectP)
{ {
(void)object;
int i; int i;
uint8_t result = COAP_404_NOT_FOUND; DEBUG("[lwm2m:device:read]\n");
dev_data_t *data = (dev_data_t *)objectP->userData;
(void)data;
/* Single instance object */ /* Single instance object */
if (instance_id != 0) { if (instance_id != 0) {
goto out; return COAP_404_NOT_FOUND;
} }
/* Full object requested */ /* Full object requested */
if (*num_dataP == 0) { if (*num_data == 0) {
DEBUG("[lwm2m:device:read] all resources are requested\n");
/* This list must contain all readable resources */ /* This list must contain all readable resources */
uint16_t resList[] = { uint16_t resList[] = {
LWM2M_RES_MANUFACTURER, LWM2M_RES_MODEL_NO, LWM2M_RES_SERIAL, LWM2M_RES_MANUFACTURER, LWM2M_RES_MODEL_NO, LWM2M_RES_SERIAL,
@ -138,109 +189,103 @@ static uint8_t prv_device_read(uint16_t instance_id, int *num_dataP,
LWM2M_RES_BINDINGS, LWM2M_RES_TYPE, LWM2M_RES_ERROR_CODE, LWM2M_RES_BINDINGS, LWM2M_RES_TYPE, LWM2M_RES_ERROR_CODE,
}; };
int cnt = ARRAY_SIZE(resList); int cnt = ARRAY_SIZE(resList);
*data_arrayP = lwm2m_data_new(cnt); *data_array = lwm2m_data_new(cnt);
if (*data_arrayP == NULL) { *num_data = cnt;
result = COAP_500_INTERNAL_SERVER_ERROR;
goto out; if (*data_array == NULL) {
DEBUG("[lwm2m:device:read] could not allocate data array\n");
return COAP_500_INTERNAL_SERVER_ERROR;
} }
*num_dataP = cnt;
for (i = 0; i < cnt; i++) { for (i = 0; i < cnt; i++) {
(*data_arrayP)[i].id = resList[i]; (*data_array)[i].id = resList[i];
} }
} }
for (i = 0; i < *num_dataP; i++) { for (i = 0; i < *num_data; i++) {
switch ((*data_arrayP)[i].id) { lwm2m_data_t *data = &(*data_array)[i];
/* Exec resources */
case LWM2M_RES_REBOOT: DEBUG("[lwm2m:device:read] reading resource %d\n", data->id);
case LWM2M_RES_FRESET: switch (data->id) {
case LWM2M_RES_ERROR_CODE_RESET: /* Exec resources, can't be read */
result = COAP_405_METHOD_NOT_ALLOWED; case LWM2M_RES_REBOOT:
goto out; case LWM2M_RES_FRESET:
break; case LWM2M_RES_ERROR_CODE_RESET:
case LWM2M_RES_ERROR_CODE: return COAP_405_METHOD_NOT_ALLOWED;
/* TODO: Here some error reporting should be implemented. */ break;
lwm2m_data_encode_int(LWM2M_DEVICE_ERR_NO_ERR, *data_arrayP + i);
result = COAP_205_CONTENT; case LWM2M_RES_ERROR_CODE:
break; /* TODO: Here some error reporting should be implemented. For now returning no error */
/* The rest are either static or not defined resources */ lwm2m_data_encode_int(LWM2M_DEVICE_ERR_NO_ERR, data);
default: break;
if (_static_resources[(*data_arrayP)[i].id]) {
lwm2m_data_encode_string( case LWM2M_RES_MANUFACTURER:
_static_resources[(*data_arrayP)[i].id], lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_MANUFACTURER, data);
*data_arrayP + i); break;
result = COAP_205_CONTENT;
} case LWM2M_RES_MODEL_NO:
else { lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_MODEL, data);
result = COAP_404_NOT_FOUND; break;
goto out;
} case LWM2M_RES_SERIAL:
lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_SERIAL, data);
break;
case LWM2M_RES_FW_VER:
lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_FW_VERSION, data);
break;
case LWM2M_RES_BINDINGS:
lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_BINDINGS, data);
break;
case LWM2M_RES_TYPE:
lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_TYPE, data);
break;
case LWM2M_RES_HW_VERSION:
lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_HW_VERSION, data);
break;
case LWM2M_RES_SW_VERSION:
lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_SW_VERSION, data);
break;
case LWM2M_DEVICE_RESOURCES:
lwm2m_data_encode_string(NULL, data);
break;
/* The rest are not defined resources */
default:
return COAP_404_NOT_FOUND;
} }
} }
out: return COAP_205_CONTENT;
return result;
} }
static uint8_t prv_device_write(uint16_t instance_id, int num_data, static uint8_t _execute_cb(uint16_t instance_id, uint16_t resource_id, uint8_t *buffer, int length,
lwm2m_data_t *data_array, lwm2m_object_t *object)
lwm2m_object_t *objectP)
{ {
dev_data_t *data = (dev_data_t *)objectP->userData;
(void)data;
(void)instance_id;
(void)num_data;
(void)data_array;
if (data_array[0].id < LWM2M_DEVICE_RESOURCES) {
/* for now not writing resources */
return COAP_405_METHOD_NOT_ALLOWED;
}
else {
return COAP_404_NOT_FOUND;
}
}
static uint8_t prv_device_execute(uint16_t instance_id, uint16_t resource_id,
uint8_t *buffer, int length,
lwm2m_object_t *objectP)
{
uint8_t result;
dev_data_t *data = (dev_data_t *)objectP->userData;
(void)data;
(void)buffer; (void)buffer;
(void)length; (void)object;
(void)objectP;
/* single instance object */ /* single instance object */
if (instance_id != 0) { if (instance_id != 0) {
result = COAP_404_NOT_FOUND; return COAP_404_NOT_FOUND;
goto err_out;
} }
if (length != 0) { if (length != 0) {
result = COAP_400_BAD_REQUEST; return COAP_400_BAD_REQUEST;
goto err_out;
} }
switch (resource_id) { /* for now only rebooting is available */
case LWM2M_RES_REBOOT: if (resource_id == LWM2M_RES_REBOOT) {
reboot = true; reboot = true;
result = COAP_204_CHANGED; return COAP_204_CHANGED;
break;
case LWM2M_RES_ERROR_CODE_RESET:
/* TODO */
case LWM2M_RES_FRESET:
/* TODO Callback? */
default:
result = COAP_405_METHOD_NOT_ALLOWED;
} }
err_out: return COAP_405_METHOD_NOT_ALLOWED;
return result;
} }
/* /*
@ -251,63 +296,10 @@ bool lwm2m_device_reboot_requested(void)
return reboot; return reboot;
} }
lwm2m_object_t *lwm2m_get_object_device(void) lwm2m_object_t *lwm2m_object_device_init(lwm2m_client_data_t *client_data)
{ {
lwm2m_object_t *obj; assert(client_data);
obj = (lwm2m_object_t *)lwm2m_malloc(sizeof(lwm2m_object_t)); _device_object.userData = client_data;
return &_device_object;
if (obj == NULL) {
goto err_out;
}
memset(obj, 0, sizeof(lwm2m_object_t));
obj->instanceList = (lwm2m_list_t *)lwm2m_malloc(sizeof(lwm2m_list_t));
if (obj->instanceList == NULL) {
goto free_obj;
}
memset(obj->instanceList, 0, sizeof(lwm2m_list_t));
obj->objID = LWM2M_DEVICE_OBJECT_ID;
obj->readFunc = prv_device_read;
obj->writeFunc = prv_device_write;
obj->executeFunc = prv_device_execute;
obj->discoverFunc = prv_device_discover;
/* Don't allocate memory for stuff that isn't used at the moment */
/* obj->userData = lwm2m_malloc(sizeof(dev_data_t)); */
/* if (obj->userData == NULL) { */
/* goto free_ilist; */
/* } */
/* */
/* memset(obj->userData, 0, sizeof(dev_data_t)); */
/* INT USER DATA HERE */
return obj;
/* free_ilist: */
/* lwm2m_free(obj->instanceList); */
free_obj:
lwm2m_free(obj);
err_out:
return NULL;
}
void lwm2m_free_object_device(lwm2m_object_t *obj)
{
if (obj == NULL) {
return;
}
if (obj->userData) {
lwm2m_free(obj->userData);
}
if (obj->instanceList) {
lwm2m_free(obj->instanceList);
}
lwm2m_free(obj);
} }

View File

@ -0,0 +1,913 @@
/*
* Copyright (C) 2024 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @{
* @ingroup lwm2m_objects_security
*
* @file
* @brief Security object implementation for LwM2M client using Wakaama
*
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
* @}
*/
#include "liblwm2m.h"
#include "objects/security.h"
#include "lwm2m_client_config.h"
#include "lwm2m_client.h"
#include "kernel_defines.h"
#include "net/credman.h"
#include "mutex.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#define ENABLE_DEBUG 0
#include "debug.h"
#define _USED_INSTANCES(_obj) (_obj.wakaama_object.instanceList)
#define _FREE_INSTANCES(_obj) (_obj.free_instances)
/**
* @brief Descriptor of a LwM2M Security object instance (Object ID = 0)
*/
typedef struct lwm2m_obj_security_inst {
/**
* @brief Linked list handle.
*/
lwm2m_list_t list;
/**
* @brief Server URI.
*/
char uri[CONFIG_LWM2M_URI_MAX_SIZE];
/**
* @brief Indicates if the server associated to the security instance is a Bootstrap-Server.
*/
bool is_bootstrap;
/**
* @brief Security mode to use with the server.
*/
uint8_t security_mode;
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
/**
* @brief Tag of the credential to use with the server.
*/
credman_tag_t cred_tag;
/**
* @brief Buffer for the public key or ID resource.
*/
uint8_t pub_key_or_id[CONFIG_LWM2M_OBJ_SECURITY_PUB_KEY_ID_BUFSIZE];
/**
* @brief Bytes used in @ref lwm2m_obj_security_inst_t::pub_key_or_id.
*/
size_t pub_key_or_id_len;
/**
* @brief Buffer for the server public key resource.
*/
uint8_t server_pub_key[CONFIG_LWM2M_OBJ_SECURITY_SERVER_PUB_KEY_BUFSIZE];
/**
* @brief Bytes used in @ref lwm2m_obj_security_inst_t::server_pub_key.
*/
size_t server_pub_key_len;
/**
* @brief Credman public key structure for the server.
*/
ecdsa_public_key_t server_credman_pub_key;
/**
* @brief Buffer for the secret or private key resource.
*/
uint8_t secret_key[CONFIG_LWM2M_OBJ_SECURITY_SEC_KEY_BUFSIZE];
/**
* @brief Bytes used in @ref lwm2m_obj_security_inst_t::secret_key.
*/
size_t secret_key_len;
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
/**
* @brief Short ID to reference the server.
*/
uint16_t short_id;
/**
* @brief Hold off time for registration.
*/
uint32_t client_hold_off_time;
/**
* @brief Timeout for Bootstrap-Server account deletion.
*/
uint32_t bs_account_timeout;
} lwm2m_obj_security_inst_t;
/**
* @brief 'Read' callback for the security object.
*
* @param[in] instance_id ID of the instance to read
* @param[in, out] num_data Number of resources requested. 0 means all.
* @param[in, out] data_array Initialized data array to output the values,
* when @p num_data != 0. Uninitialized otherwise.
* @param[in] object Security object pointer
*
* @retval COAP_205_CONTENT on success
* @retval COAP_404_NOT_FOUND when resource can't be found
* @retval COAP_500_INTERNAL_SERVER_ERROR otherwise
*/
static uint8_t _read_cb(uint16_t instance_id, int *num_data, lwm2m_data_t *data_array[],
lwm2m_object_t *object);
/**
* @brief 'Write' callback for the security object.
*
* @param[in] instance_id ID of the instance to write to
* @param[in] num_data Number of resources to write
* @param[in] data_array Array of data to write
* @param[in] object Security object pointer
*
* @retval COAP_204_CHANGED on success
* @retval COAP_400_BAD_REQUEST otherwise
*/
static uint8_t _write_cb(uint16_t instance_id, int num_data, lwm2m_data_t *data_array,
lwm2m_object_t *object);
/**
* @brief 'Delete' callback for the security object.
*
* @param[in] instance_id ID of the instance to delete
* @param[in] object Security object pointer
*
* @retval COAP_202_DELETED on success
* @retval COAP_404_NOT_FOUND when the instance can't be found
*/
static uint8_t _delete_cb(uint16_t instance_id, lwm2m_object_t *object);
/**
* @brief 'Create' callback for the security object.
*
* @param[in] instance_id ID of the instance to create
* @param[in] num_data Number of resources to write
* @param[in] data_array Array of data to write
* @param[in] object Security object pointer
*
* @retval COAP_201_CREATED on success
* @retval COAP_500_INTERNAL_SERVER_ERROR otherwise
*/
static uint8_t _create_cb(uint16_t instance_id, int num_data, lwm2m_data_t *data_array,
lwm2m_object_t *object);
/**
* @brief Get a value from a security object instance.
*
* @param data[in, out] Data structure indicating the id of the resource
* to get the value of. It will contain the value if
* successful.
* @param instance[in] Instance to get the data from.
* @retval 0 on success
* @retval <0 otherwise
*/
static int _get_value(lwm2m_data_t *data, lwm2m_obj_security_inst_t *instance);
/**
* @brief Initialize a new instance with the given arguments.
*
* @param instance[out] Instance to initialize.
* @param instance_id[in] ID of the instance.
* @param args[in] Arguments to initialize the instance with.
*
* @retval 0 on success
* @retval -ENOMEM if there is no memory available to copy credentials
* @retval -EINVAL if the arguments are invalid
*/
static int _initialize_new_instance(lwm2m_obj_security_inst_t *instance, uint16_t instance_id,
const lwm2m_obj_security_args_t *args);
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
/**
* @brief Update a credential in the credman registry with the current instance information.
*
* @param[in] instance Instance to update the credential to.
*
* @retval 0 on success
* @retval <0 otherwise
*/
static int _update_credential(lwm2m_obj_security_inst_t *instance);
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
struct lwm2m_security_object {
lwm2m_object_t wakaama_object; /**< Wakaama internal object */
mutex_t lock; /**< mutex for the instances access */
lwm2m_obj_security_inst_t *free_instances; /**< list of free instances */
lwm2m_obj_security_inst_t instances[CONFIG_LWM2M_OBJ_SECURITY_INSTANCES_MAX]; /**< instances */
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
credman_tag_t tag_count; /**< counter for the credential tags */
#endif
};
/**
* @brief Implementation of the object interface for the Security Object.
*/
static struct lwm2m_security_object _security_object = {
.lock = MUTEX_INIT,
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
.tag_count= CONFIG_LWM2M_CREDMAN_TAG_BASE,
#endif
.wakaama_object = {
.next = NULL,
.objID = LWM2M_SECURITY_OBJECT_ID,
.instanceList = NULL,
.readFunc = _read_cb,
.writeFunc = _write_cb,
.createFunc = _create_cb,
.deleteFunc = _delete_cb,
.executeFunc = NULL,
.discoverFunc = NULL,
.userData = NULL,
}
};
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
static int _update_credential(lwm2m_obj_security_inst_t *instance)
{
assert(instance);
credman_credential_t cred;
credman_type_t type;
if (instance->security_mode == LWM2M_SECURITY_MODE_PRE_SHARED_KEY) {
type = CREDMAN_TYPE_PSK;
}
else {
type = CREDMAN_TYPE_ECDSA;
}
credman_delete(instance->cred_tag, type);
if (instance->cred_tag == CREDMAN_TAG_EMPTY) {
instance->cred_tag = ++_security_object.tag_count;
}
cred.type = type;
cred.tag = instance->cred_tag;
DEBUG("[lwm2m:security]: updating credential with tag %d\n", cred.tag);
if (type == CREDMAN_TYPE_PSK) {
DEBUG("[lwm2m:security]: PSK ID: %.*s\n", (unsigned)instance->pub_key_or_id_len, instance->pub_key_or_id);
DEBUG("[lwm2m:security]: PSK Key: %.*s\n", (unsigned)instance->secret_key_len, instance->secret_key);
cred.params.psk.id.s = instance->pub_key_or_id;
cred.params.psk.id.len = instance->pub_key_or_id_len;
cred.params.psk.key.s = instance->secret_key;
cred.params.psk.key.len = instance->secret_key_len;
}
else {
DEBUG("[lwm2m:security]: Server pub. key: [");
for (size_t i = 0; i < instance->server_pub_key_len; i++) {
DEBUG("0x%02x ", instance->server_pub_key[i]);
}
DEBUG("]\n");
DEBUG("[lwm2m:security]: Pub. key: [");
for (size_t i = 0; i < instance->pub_key_or_id_len; i++) {
DEBUG("0x%02x ", instance->pub_key_or_id[i]);
}
DEBUG("]\n");
DEBUG("[lwm2m:security]: Priv. key: [");
for (size_t i = 0; i < instance->secret_key_len; i++) {
DEBUG("0x%02x ", instance->secret_key[i]);
}
DEBUG("]\n");
int res = credman_load_public_key(instance->server_pub_key, instance->server_pub_key_len,
&instance->server_credman_pub_key);
if (res != CREDMAN_OK) {
DEBUG("[lwm2m:security]: error loading server public key (%d)\n", res);
return -1;
}
cred.params.ecdsa.client_keys = &instance->server_credman_pub_key;
cred.params.ecdsa.client_keys_size = 1;
res = credman_load_private_ecc_key(instance->secret_key, instance->secret_key_len, &cred);
if (res != CREDMAN_OK) {
DEBUG("[lwm2m:security]: error loading private key (%d)\n", res);
return -1;
}
res = credman_load_public_key(instance->pub_key_or_id, instance->pub_key_or_id_len,
&(cred.params.ecdsa.public_key));
if (res != CREDMAN_OK) {
DEBUG("[lwm2m:security]: error loading own public key (%d)\n", res);
return -1;
}
}
lwm2m_client_add_credential(instance->cred_tag);
return credman_add(&cred) == CREDMAN_OK ? 0 : -1;
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
static int _get_value(lwm2m_data_t *data, lwm2m_obj_security_inst_t *instance)
{
assert(data);
assert(instance);
/* resource IDs are defined by Wakaama in liblwm2m.h */
switch (data->id) {
case LWM2M_SECURITY_URI_ID:
lwm2m_data_encode_string(instance->uri, data);
break;
case LWM2M_SECURITY_BOOTSTRAP_ID:
lwm2m_data_encode_bool(instance->is_bootstrap, data);
break;
case LWM2M_SECURITY_SHORT_SERVER_ID:
lwm2m_data_encode_int(instance->short_id, data);
break;
case LWM2M_SECURITY_HOLD_OFF_ID:
lwm2m_data_encode_int(instance->client_hold_off_time, data);
break;
case LWM2M_SECURITY_BOOTSTRAP_TIMEOUT_ID:
lwm2m_data_encode_int(instance->bs_account_timeout, data);
break;
case LWM2M_SECURITY_SECURITY_ID:
lwm2m_data_encode_int(instance->security_mode, data);
break;
case LWM2M_SECURITY_PUBLIC_KEY_ID:
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
lwm2m_data_encode_opaque(instance->pub_key_or_id, instance->pub_key_or_id_len, data);
#else
return COAP_404_NOT_FOUND;
#endif
break;
case LWM2M_SECURITY_SECRET_KEY_ID:
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
lwm2m_data_encode_opaque(instance->secret_key, instance->secret_key_len, data);
#else
return COAP_404_NOT_FOUND;
#endif
break;
case LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID:
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
lwm2m_data_encode_opaque(instance->server_pub_key, instance->server_pub_key_len, data);
#else
return COAP_404_NOT_FOUND;
#endif
break;
/* not implemented */
case LWM2M_SECURITY_SMS_SECURITY_ID:
case LWM2M_SECURITY_SMS_KEY_PARAM_ID:
case LWM2M_SECURITY_SMS_SECRET_KEY_ID:
case LWM2M_SECURITY_SMS_SERVER_NUMBER_ID:
return COAP_404_NOT_FOUND;
default:
return COAP_404_NOT_FOUND;
}
return COAP_205_CONTENT;
}
static uint8_t _read_cb(uint16_t instance_id, int *num_data, lwm2m_data_t *data_array[],
lwm2m_object_t *object)
{
lwm2m_obj_security_inst_t *instance;
uint8_t result;
int i = 0;
/* try to get the requested instance from the object list */
instance = (lwm2m_obj_security_inst_t *)lwm2m_list_find(object->instanceList, instance_id);
if (NULL == instance) {
result = COAP_404_NOT_FOUND;
goto out;
}
/* if the number of resources is not specified, we need to read all resources */
if (!*num_data) {
DEBUG("[security:read] all resources are read\n");
const uint16_t resList[] = {
LWM2M_SECURITY_URI_ID,
LWM2M_SECURITY_BOOTSTRAP_ID,
LWM2M_SECURITY_SECURITY_ID,
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
LWM2M_SECURITY_PUBLIC_KEY_ID,
LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID,
LWM2M_SECURITY_SECRET_KEY_ID,
#endif
/* LWM2M_SECURITY_SMS_SECURITY_ID, */
/* LWM2M_SECURITY_SMS_KEY_PARAM_ID, */
/* LWM2M_SECURITY_SMS_SECRET_KEY_ID, */
/* LWM2M_SECURITY_SMS_SERVER_NUMBER_ID, */
LWM2M_SECURITY_SHORT_SERVER_ID,
LWM2M_SECURITY_HOLD_OFF_ID,
LWM2M_SECURITY_BOOTSTRAP_TIMEOUT_ID
};
/* try to allocate data structures for all resources */
int resNum = ARRAY_SIZE(resList);
*data_array = lwm2m_data_new(resNum);
if (NULL == *data_array) {
result = COAP_500_INTERNAL_SERVER_ERROR;
goto out;
}
/* indicate the number of resources that are returned */
*num_data = resNum;
/* prepare the resource ID of all resources for the request */
for (i = 0 ; i < resNum ; i++) {
(*data_array)[i].id = resList[i];
}
}
/* the data structures in data_array contain the IDs of the resources to get the values of */
i = 0;
do {
DEBUG("[security:read] read: %d\n", (*data_array)[i].id);
result = _get_value(&(*data_array)[i], instance);
i++;
} while (i < *num_data && COAP_205_CONTENT == result);
out:
return result;
}
static uint8_t _write_cb(uint16_t instance_id, int num_data, lwm2m_data_t *data_array,
lwm2m_object_t *object)
{
lwm2m_obj_security_inst_t *instance;
int64_t value;
uint8_t result = COAP_404_NOT_FOUND;
int i = 0;
DEBUG("[lwm2m:security:write]: looking for instance %d\n", instance_id);
/* try to get the requested instance from the object list */
instance = (lwm2m_obj_security_inst_t *)lwm2m_list_find(object->instanceList, instance_id);
if (!instance) {
DEBUG("[lwm2m:security:write]: not found\n");
goto out;
}
/* iterate over the array of data to write */
do {
lwm2m_data_t *data = &data_array[i];
switch (data->id) {
case LWM2M_SECURITY_URI_ID:
DEBUG("[lwm2m:security:write]: writing URI\n");
if (data->value.asBuffer.length > CONFIG_LWM2M_URI_MAX_SIZE - 1) {
result = COAP_400_BAD_REQUEST;
}
strncpy(instance->uri, (char *)data->value.asBuffer.buffer,
data->value.asBuffer.length);
instance->uri[data->value.asBuffer.length] = '\0';
result = COAP_204_CHANGED;
break;
case LWM2M_SECURITY_BOOTSTRAP_ID:
DEBUG("[lwm2m:security:write]: writing bootstrap\n");
if (lwm2m_data_decode_bool(data, &(instance->is_bootstrap)) == 1) {
result = COAP_204_CHANGED;
}
else {
result = COAP_400_BAD_REQUEST;
}
break;
case LWM2M_SECURITY_SECURITY_ID:
DEBUG("[lwm2m:security:write]: writing sec. mode\n");
if (lwm2m_data_decode_int(data, &value) == 1) {
/* check if it is a valid security mode */
if (LWM2M_SECURITY_MODE_NONE == value ||
LWM2M_SECURITY_MODE_PRE_SHARED_KEY == value ||
LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY == value ||
LWM2M_SECURITY_MODE_CERTIFICATE == value) {
instance->security_mode = value;
result = COAP_204_CHANGED;
break;
}
}
result = COAP_400_BAD_REQUEST;
break;
case LWM2M_SECURITY_SHORT_SERVER_ID:
DEBUG("[lwm2m:security:write]: writing short ID\n");
if (lwm2m_data_decode_int(data, &value) == 1) {
/* check valid range of value */
if (value > 0 && value < UINT16_MAX) {
instance->short_id = value;
result = COAP_204_CHANGED;
break;
}
}
result = COAP_400_BAD_REQUEST;
break;
case LWM2M_SECURITY_HOLD_OFF_ID:
DEBUG("[lwm2m:security:write]: writing hold off time\n");
if (lwm2m_data_decode_int(data, &value) == 1) {
/* check valid range of value */
if (value >= 0 && value <= UINT32_MAX) {
instance->client_hold_off_time = value;
result = COAP_204_CHANGED;
break;
}
}
result = COAP_400_BAD_REQUEST;
break;
case LWM2M_SECURITY_BOOTSTRAP_TIMEOUT_ID:
DEBUG("[lwm2m:security:write]: writing bootstrap timeout\n");
if (lwm2m_data_decode_int(data, &value) == 1) {
/* check valid range of value */
if (value >= 0 && value <= UINT32_MAX) {
instance->bs_account_timeout = value;
result = COAP_204_CHANGED;
break;
}
}
result = COAP_400_BAD_REQUEST;
break;
case LWM2M_SECURITY_PUBLIC_KEY_ID:
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
DEBUG("[lwm2m:security:write]: writing pub. key or ID\n");
if (data->value.asBuffer.length >
CONFIG_LWM2M_OBJ_SECURITY_PUB_KEY_ID_BUFSIZE) {
result = COAP_500_INTERNAL_SERVER_ERROR;
}
/* copy the new value */
memcpy(instance->pub_key_or_id, data->value.asBuffer.buffer,
data->value.asBuffer.length);
/* if the size changed we need to modify the registered credential */
if (instance->pub_key_or_id_len != data->value.asBuffer.length) {
instance->pub_key_or_id_len = data->value.asBuffer.length;
_update_credential(instance);
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
result = COAP_204_CHANGED;
break;
case LWM2M_SECURITY_SECRET_KEY_ID:
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
DEBUG("[lwm2m:security:write]: writing sec. key\n");
if (data->value.asBuffer.length >
CONFIG_LWM2M_OBJ_SECURITY_SEC_KEY_BUFSIZE) {
result = COAP_500_INTERNAL_SERVER_ERROR;
}
/* copy the new value */
memcpy(instance->secret_key, data->value.asBuffer.buffer,
data->value.asBuffer.length);
/* if the size changed we need to modify the registered credential */
if (instance->secret_key_len != data->value.asBuffer.length) {
instance->secret_key_len = data->value.asBuffer.length;
_update_credential(instance);
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
result = COAP_204_CHANGED;
break;
case LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID:
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
DEBUG("[lwm2m:security:write]: writing server pub. key\n");
if (data->value.asBuffer.length >
CONFIG_LWM2M_OBJ_SECURITY_SERVER_PUB_KEY_BUFSIZE) {
result = COAP_500_INTERNAL_SERVER_ERROR;
}
/* copy the new value */
memcpy(instance->server_pub_key, data->value.asBuffer.buffer,
data->value.asBuffer.length);
/* if the size changed we need to modify the registered credential */
if (instance->server_pub_key_len != data->value.asBuffer.length) {
instance->server_pub_key_len = data->value.asBuffer.length;
_update_credential(instance);
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
result = COAP_204_CHANGED;
break;
/* not implemented, ignore for now */
case LWM2M_SECURITY_SMS_SECURITY_ID:
case LWM2M_SECURITY_SMS_KEY_PARAM_ID:
case LWM2M_SECURITY_SMS_SECRET_KEY_ID:
case LWM2M_SECURITY_SMS_SERVER_NUMBER_ID:
result = COAP_204_CHANGED;
break;
default:
DEBUG("[lwm2m:security:write]: unknown resource %d\n", data->id);
result = COAP_404_NOT_FOUND;
}
i++;
} while (i < num_data && result == COAP_204_CHANGED);
DEBUG("[lwm2m:security:write]: done\n");
out:
return result;
}
static uint8_t _delete_cb(uint16_t instance_id, lwm2m_object_t *object)
{
uint8_t result = COAP_404_NOT_FOUND;
lwm2m_obj_security_inst_t *instance;
mutex_lock(&_security_object.lock);
DEBUG("[lwm2m:security:write]: looking for instance %d\n", instance_id);
/* try to remove the requested instance from the list */
object->instanceList = LWM2M_LIST_RM(object->instanceList, instance_id, &instance);
/* check if the instance was found */
if (NULL == instance) {
result = COAP_404_NOT_FOUND;
goto free_out;
}
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
/* if there is an associated credential, de-register */
if (instance->cred_tag != CREDMAN_TAG_EMPTY) {
credman_type_t type = instance->security_mode == LWM2M_SECURITY_MODE_PRE_SHARED_KEY ?
CREDMAN_TYPE_PSK : CREDMAN_TYPE_ECDSA;
credman_delete(instance->cred_tag, type);
lwm2m_client_remove_credential(instance->cred_tag);
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
/* add instance to free instances list */
instance->list.id = UINT16_MAX;
_FREE_INSTANCES(_security_object) = (lwm2m_obj_security_inst_t *) LWM2M_LIST_ADD(
_FREE_INSTANCES(_security_object), instance);
result = COAP_202_DELETED;
free_out:
mutex_unlock(&_security_object.lock);
return result;
}
static uint8_t _create_cb(uint16_t instance_id, int num_data, lwm2m_data_t *data_array,
lwm2m_object_t *object)
{
lwm2m_obj_security_inst_t *instance;
uint8_t result;
mutex_lock(&_security_object.lock);
/* check that the ID is free to use */
if (LWM2M_LIST_FIND(_USED_INSTANCES(_security_object), instance_id ) != NULL) {
DEBUG("[lwm2m:security]: instance ID %" PRIu16 " already in use\n", instance_id);
result = COAP_400_BAD_REQUEST;
goto free_out;
}
/* try to allocate an instance, by popping a free node from the list */
_FREE_INSTANCES(_security_object) = (lwm2m_obj_security_inst_t *) lwm2m_list_remove(
(lwm2m_list_t *) _FREE_INSTANCES(_security_object),
UINT16_MAX,
(lwm2m_list_t **) &instance
);
if (!instance) {
DEBUG("[lwm2m:security:create] can't allocate free instance\n");
result = COAP_500_INTERNAL_SERVER_ERROR;
goto free_out;
}
memset(instance, 0, sizeof(lwm2m_obj_security_inst_t));
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
instance->cred_tag = CREDMAN_TAG_EMPTY;
#endif
/* add to the object instance list */
instance->list.id = instance_id;
object->instanceList = LWM2M_LIST_ADD(object->instanceList, instance);
/* write incoming data to the instance */
result = _write_cb(instance_id, num_data, data_array, object);
if (result != COAP_204_CHANGED) {
_delete_cb(instance_id, object);
}
else {
result = COAP_201_CREATED;
goto free_out;
}
free_out:
mutex_unlock(&_security_object.lock);
return result;
}
lwm2m_object_t *lwm2m_object_security_init(lwm2m_client_data_t *client_data)
{
/* initialize the instances */
for (unsigned i = 0; i < CONFIG_LWM2M_OBJ_SECURITY_INSTANCES_MAX; i++) {
_security_object.instances[i].list.next = NULL;
_security_object.instances[i].list.id = UINT16_MAX;
_FREE_INSTANCES(_security_object) = (lwm2m_obj_security_inst_t *) LWM2M_LIST_ADD(
_FREE_INSTANCES(_security_object), &(_security_object.instances[i]));
}
_security_object.wakaama_object.userData = client_data;
return &(_security_object.wakaama_object);
}
static int _initialize_new_instance(lwm2m_obj_security_inst_t *instance, uint16_t instance_id,
const lwm2m_obj_security_args_t *args)
{
memset(instance, 0, sizeof(lwm2m_obj_security_inst_t));
instance->list.id = instance_id;
instance->short_id = args->server_id;
instance->security_mode = args->security_mode;
instance->is_bootstrap = args->is_bootstrap;
instance->client_hold_off_time = args->client_hold_off_time;
instance->bs_account_timeout = args->bootstrap_account_timeout;
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
instance->cred_tag = CREDMAN_TAG_EMPTY;
#endif
/* copy the URI locally */
size_t uri_len = strlen(args->server_uri);
if (uri_len > CONFIG_LWM2M_URI_MAX_SIZE - 1) {
DEBUG("[lwm2m:security]: can't copy URI, not enough space\n");
return -ENOMEM;
}
strncpy(instance->uri, args->server_uri, uri_len);
instance->uri[uri_len] = '\0';
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
if (LWM2M_SECURITY_MODE_NONE != args->security_mode) {
if (LWM2M_SECURITY_MODE_CERTIFICATE == args->security_mode) {
DEBUG("[lwm2m:security]: certificate mode not supported\n");
return -EINVAL;
}
/* copy keys locally */
if (LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY == args->security_mode) {
if (!args->server_pub_key ||
args->server_pub_key_len > CONFIG_LWM2M_OBJ_SECURITY_SERVER_PUB_KEY_BUFSIZE) {
DEBUG("[lwm2m:security]: Invalid server public key\n");
return -EINVAL;
}
memcpy(instance->server_pub_key, args->server_pub_key, args->server_pub_key_len);
instance->server_pub_key_len = args->server_pub_key_len;
}
if (!args->pub_key_or_id ||
args->pub_key_or_id_len > CONFIG_LWM2M_OBJ_SECURITY_PUB_KEY_ID_BUFSIZE) {
DEBUG("[lwm2m:security]: Invalid public key or ID\n");
return -EINVAL;
}
memcpy(instance->pub_key_or_id, args->pub_key_or_id, args->pub_key_or_id_len);
instance->pub_key_or_id_len = args->pub_key_or_id_len;
if (!args->secret_key ||
args->secret_key_len > CONFIG_LWM2M_OBJ_SECURITY_SEC_KEY_BUFSIZE) {
DEBUG("[lwm2m:security]: Invalid secret key\n");
return -EINVAL;
}
memcpy(instance->secret_key, args->secret_key, args->secret_key_len);
instance->secret_key_len = args->secret_key_len;
/* assign a credential tag */
instance->cred_tag = ++_security_object.tag_count;
if (_update_credential(instance) < 0) {
DEBUG("[lwm2m:security]: could not register the credential\n");
return -ENOMEM;
}
}
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
return 0;
}
int lwm2m_object_security_instance_create(const lwm2m_obj_security_args_t *args,
int32_t instance_id)
{
assert(args);
int result = -ENOMEM;
uint16_t _instance_id;
lwm2m_obj_security_inst_t *instance = NULL;
/* lock object */
mutex_lock(&_security_object.lock);
/* some sanity checks */
if (!args || !args->server_id || !args->server_uri) {
DEBUG("[lwm2m:security]: invalid arguments\n");
result = -EINVAL;
goto free_out;
}
DEBUG("[lwm2m:security]: creating new instance\n");
/* determine ID for new instance */
if (instance_id < 0) {
_instance_id = lwm2m_list_newId((lwm2m_list_t *)_USED_INSTANCES(_security_object));
}
else {
/* sanity check */
if (instance_id >= (UINT16_MAX - 1)) {
DEBUG("[lwm2m:security]: instance ID %" PRIi32 " is too big\n", instance_id);
result = -EINVAL;
goto free_out;
}
_instance_id = (uint16_t)instance_id;
/* check that the ID is free to use */
if (LWM2M_LIST_FIND(_USED_INSTANCES(_security_object), _instance_id ) != NULL) {
DEBUG("[lwm2m:security]: instance ID %" PRIi32 " already in use\n", instance_id);
result = -EINVAL;
goto free_out;
}
}
/* try to allocate an instance, by popping a free node from the list */
_FREE_INSTANCES(_security_object) = (lwm2m_obj_security_inst_t *) lwm2m_list_remove(
(lwm2m_list_t *) _FREE_INSTANCES(_security_object),
UINT16_MAX,
(lwm2m_list_t **) &instance
);
if (!instance) {
DEBUG("[lwm2m:security]: can't allocate new instance\n");
goto free_out;
}
result = _initialize_new_instance(instance, _instance_id, args);
if (result < 0) {
DEBUG("[lwm2m:security]: could not initialize new instance\n");
goto free_out;
}
DEBUG("[lwm2m:security]: added instance with URI: %s\n", instance->uri);
/* add the new instance to the list */
_USED_INSTANCES(_security_object) = LWM2M_LIST_ADD(_USED_INSTANCES(_security_object), instance);
result = instance->list.id;
free_out:
mutex_unlock(&_security_object.lock);
return result;
}
credman_tag_t lwm2m_object_security_get_credential(uint16_t instance_id)
{
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
lwm2m_obj_security_inst_t *instance;
/* try to get the requested instance from the object list */
instance = (lwm2m_obj_security_inst_t *)lwm2m_list_find(_USED_INSTANCES(_security_object),
instance_id);
if (NULL == instance) {
DEBUG("[lwm2m:security]: no instance %d\n", instance_id);
return CREDMAN_TAG_EMPTY;
}
return instance->cred_tag;
#else
(void) instance_id;
return CREDMAN_TAG_EMPTY;
#endif /* MODULE_WAKAAMA_CLIENT_DTLS */
}

View File

@ -1,7 +1,119 @@
/** /**
* @defgroup pkg_wakaama Wakaama LwM2M implementation * @defgroup pkg_wakaama LwM2M - Lightweight Machine to Machine
* @ingroup pkg * @ingroup pkg
* @ingroup net * @ingroup net
* @brief Provides the Wakaama implementation of LwM2M * @brief LwM2M implementation based on the Wakaama package
* @see https://github.com/eclipse/wakaama *
*/ * Lightweight Machine to Machine is a device management protocol designed for sensor networks,
* designed for remote management of M2M devices and related service enablement. It defines an
* extensible resource and data model and builds top of CoAP. LwM2M has been specified by the
* OMA SpecWorks Device Management Working Group. The specification is freely available
* [here](http://openmobilealliance.org/wp/index.html).
*
* For a list of the supported objects see @ref lwm2m_objects.
* The client implementation is based on the Eclipse
* [Wakaama project](https://github.com/eclipse/wakaama)
*
*
* ## Usage
* A LwM2M Client organizes resources as object instances. The LwM2M engine is independent of the
* objects that the client exposes, but it needs at least 3 mandatory ones:
* @ref lwm2m_objects_device "Device object", @ref lwm2m_objects_security "Security object" and a
* Server object.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* #include "lwm2m_client.h"
* #include "lwm2m_client_objects.h"
* #include "objects/security.h"
* #include "objects/device.h"
* #include "net/credman.h"
*
* // hold references to object handles
* lwm2m_object_t *obj_list[3];
*
* // LwM2M Client instance
* lwm2m_client_data_t client_data;
*
* // short ID for internal reference of the server
* #define CONFIG_LWM2M_SERVER_SHORT_ID 1
*
* int main(void)
* {
*
* // initiate the LwM2M Client
* lwm2m_client_init(&client_data);
*
* // arguments for instantiating a security object
* lwm2m_obj_security_args_t args = {
* .server_id = CONFIG_LWM2M_SERVER_SHORT_ID,
* .server_uri = "coap://[fd00:dead:beef::1]:5683",
* .security_mode = LWM2M_SECURITY_MODE_NONE,
* .is_bootstrap = false,
* .client_hold_off_time = 5,
* .bootstrap_account_timeout = 0
* };
*
* // get the Security object handle
* obj_list[0] = lwm2m_object_security_init(&client_data);
*
* // create a new Security object instance
* int res = lwm2m_object_security_instance_create(&args, 1);
* if (res < 0) {
* puts("Could not instantiate the security object");
* return;
* }
*
* // get the Server object handle (only single instance for now)
* obj_list[1] = lwm2m_client_get_server_object(&client_data, CONFIG_LWM2M_SERVER_SHORT_ID);
*
* // device object has a single instance. All the information for now is defined at compile-time
* obj_list[2] = lwm2m_object_device_get();
*
* // run the LwM2M client
* lwm2m_client_run(&client_data, obj_list, ARRAY_SIZE(obj_list);
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* The LwM2M Client will connect to the specified LwM2M server and register itself. After that, the
* server will be able to perform Read, Write, Create, Delete, Execute and Observe operations on the
* resources.
*
* ### DTLS support
* With the configuration above plain CoAP is used. To secure the connection with the LwM2M Server,
* a credential is needed in the Security object instance. To enable DTLS support add the module
* `wakaama_client_dtls`. This uses the @ref net_sock_dtls, so you will need to select an
* implementation of it (e.g. `USEPKG += tinydtls`). Currently Pre-Shared Key (PSK) and Raw Public
* Key (RPK) modes are supported.
*
* To see how to use DTLS credentials, go to the usage section of @ref lwm2m_objects_security.
*
* ### Using a LwM2M Bootstrap Server
* A bootstrap server gives a LwM2M deployment more flexibility. Information on how to connect to the
* LwM2M bootstrap server is defined at compile-time in the client (including URI and potentially
* needed credentials). The client connects to the bootstrap server on boot, which installs on the
* node the information needed to connect to the LwM2M servers.
*
* To enable bootstrap support, set the `LWM2M_BOOTSTRAP` option on Kconfig or set the CFLAG
* `CONFIG_LWM2M_BOOTSTRAP=1`. You will also need to specify during the security object instantiation
* that the information corresponds to a bootstrap server. DTLS is also supported for the bootstrap
* server:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* lwm2m_obj_security_args_t args = {
* .server_id = 1,
* .server_uri = "coaps://[fd00:dead:beef::1]:5684",
* .security_mode = LWM2M_SECURITY_MODE_PRE_SHARED_KEY,
* .pub_key_or_id = psk_id,
* .pub_key_or_id_len = sizeof(psk_id) - 1,
* .secret_key = psk_key,
* .secret_key_len = sizeof(psk_key) - 1,
* .is_bootstrap = true,
* .client_hold_off_time = 5,
* .bootstrap_account_timeout = 0
* };
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Keep into account, that some Sock DTLS implementations may need some extra configuration to handle
* multiple connections. See the `example/wakaama` Makefile.
*
*/

View File

@ -36,16 +36,32 @@ extern "C" {
#include "periph/pm.h" #include "periph/pm.h"
#include "net/sock/udp.h" #include "net/sock/udp.h"
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
#include "net/sock/dtls.h"
#endif
#include "lwm2m_client_config.h" #include "lwm2m_client_config.h"
#include "liblwm2m.h" #include "liblwm2m.h"
/**
* @brief Type of connection to the LwM2M server.
*/
typedef enum {
LWM2M_CLIENT_CONN_UDP, /**< UDP */
LWM2M_CLIENT_CONN_DTLS /**< DTLS over UDP */
} lwm2m_client_connection_type_t;
/** /**
* @brief Connection to server descriptor * @brief Connection to server descriptor
*/ */
typedef struct lwm2m_client_connection { typedef struct lwm2m_client_connection {
struct lwm2m_client_connection *next; /**< pointer to the next connection */ struct lwm2m_client_connection *next; /**< pointer to the next connection */
sock_udp_ep_t remote; /**< remote endpoint */ sock_udp_ep_t remote; /**< remote endpoint */
time_t last_send; /**< last sent packet to the server */ #if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS) || DOXYGEN
sock_dtls_session_t session; /**< DTLS session (needs wakaama_client_dtls module) */
#endif
lwm2m_client_connection_type_t type; /**< type of connection */
time_t last_send; /**< last sent packet to the server */
} lwm2m_client_connection_t; } lwm2m_client_connection_t;
/** /**
@ -54,6 +70,11 @@ typedef struct lwm2m_client_connection {
typedef struct { typedef struct {
kernel_pid_t pid; /**< PID of the client thread */ kernel_pid_t pid; /**< PID of the client thread */
sock_udp_t sock; /**< UDP server sock */ sock_udp_t sock; /**< UDP server sock */
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
sock_udp_t dtls_udp_sock; /**< UDP sock for DTLS */
sock_dtls_t dtls_sock; /**< DTLS client sock */
sock_udp_ep_t dtls_local_ep; /**< DTLS local endpoint */
#endif
sock_udp_ep_t local_ep; /**< Local endpoint */ sock_udp_ep_t local_ep; /**< Local endpoint */
lwm2m_context_t *lwm2m_ctx; /**< LwM2M context */ lwm2m_context_t *lwm2m_ctx; /**< LwM2M context */
lwm2m_client_connection_t *conn_list; /**< LwM2M connections list */ lwm2m_client_connection_t *conn_list; /**< LwM2M connections list */
@ -114,6 +135,30 @@ static inline lwm2m_context_t *lwm2m_client_get_ctx(
return client_data->lwm2m_ctx; return client_data->lwm2m_ctx;
} }
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS) || defined(DOXYGEN)
/**
* @brief Refreshes the client available credentials using the currently registered security objects
* @note Only available when using the module `wakaama_client_dtls`.
*/
void lwm2m_client_refresh_dtls_credentials(void);
/**
* @brief Adds a credential tag to be used with the LwM2M DTLS sock.
*
* If the tag is already available it will not be added again.
* @note Only available when using the module `wakaama_client_dtls`.
* @param[in] tag Tag to add.
*/
void lwm2m_client_add_credential(credman_tag_t tag);
/**
* @brief Removes a credential tag from the available to use with the LwM2M DTLS sock.
* @note Only available when using the module `wakaama_client_dtls`.
* @param[in] tag Tag to remove.
*/
void lwm2m_client_remove_credential(credman_tag_t tag);
#endif /* MODULE_WAKAAMA_CLIENT_DTLS || DOXYGEN */
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -59,10 +59,10 @@ extern "C" {
#endif #endif
/** /**
* @brief Device name used to register at the LwM2M server * @brief Default port for the local LwM2M CoAPs server
*/ */
#ifndef CONFIG_LWM2M_DEVICE_NAME #ifndef CONFIG_LWM2M_LOCAL_DTLS_PORT
#define CONFIG_LWM2M_DEVICE_NAME "testRIOTDevice" #define CONFIG_LWM2M_LOCAL_DTLS_PORT "5684"
#endif #endif
/** /**
@ -72,23 +72,6 @@ extern "C" {
#define CONFIG_LWM2M_DEVICE_TTL 300 #define CONFIG_LWM2M_DEVICE_TTL 300
#endif #endif
/**
* @brief LwM2M server URI to register/bootstrap with
*
* @note The host part of the URI MUST be a valid IPv6 address. Host names can
* not be resolved at this time.
*/
#ifndef CONFIG_LWM2M_SERVER_URI
#define CONFIG_LWM2M_SERVER_URI "coap://[fd00:dead:beef::1]"
#endif
/**
* @brief Numeric ID of CONFIG_LWM2M_SERVER_URI
*/
#ifndef CONFIG_LWM2M_SERVER_ID
#define CONFIG_LWM2M_SERVER_ID 10
#endif
/** /**
* @brief Alternate path to place LwM2M resources * @brief Alternate path to place LwM2M resources
*/ */
@ -97,7 +80,7 @@ extern "C" {
#endif #endif
/** /**
* @brief Define to 1 to specify that @ref CONFIG_LWM2M_SERVER_URI is a bootstrap server * @brief Define to 1 to add bootstrap server support
* *
* To define just add it to your `CFLAGS` in your application's Makefile: * To define just add it to your `CFLAGS` in your application's Makefile:
* *
@ -110,128 +93,17 @@ extern "C" {
#endif #endif
/** /**
* @brief Device object manufacturer string * @brief Number to use as base for assigning tags to @ref net_credman credentials.
*/ */
#ifndef CONFIG_LWM2M_DEVICE_MANUFACTURER #ifndef CONFIG_LWM2M_CREDMAN_TAG_BASE
#define CONFIG_LWM2M_DEVICE_MANUFACTURER "A RIOT maker" #define CONFIG_LWM2M_CREDMAN_TAG_BASE (10U)
#endif #endif
/** /**
* @brief Device object model. * @brief Maximum length of an URI allowed.
*
* @note Defaults to the board name
*/ */
#ifndef CONFIG_LWM2M_DEVICE_MODEL #ifndef CONFIG_LWM2M_URI_MAX_SIZE
#define CONFIG_LWM2M_DEVICE_MODEL RIOT_BOARD #define CONFIG_LWM2M_URI_MAX_SIZE 64
#endif
/**
* @brief Device object serial number
*/
#ifndef CONFIG_LWM2M_DEVICE_SERIAL
#define CONFIG_LWM2M_DEVICE_SERIAL "undefined"
#endif
/**
* @brief Device object firmware version
*
* @note Defaults to the running RIOT version
*/
#ifndef CONFIG_LWM2M_DEVICE_FW_VERSION
#define CONFIG_LWM2M_DEVICE_FW_VERSION RIOT_VERSION
#endif
/**
* @{
* @name Device bindings and queue modes
*
* This options are meant to be set either via Kconfig or CFLAGS:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk}
* CFLAGS += -DCONFIG_LWM2M_DEVICE_BINDING_UQ
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* @note Only one option should be selected. If more than one is defined the
* priority follows this order. By default
* @ref CONFIG_LWM2M_DEVICE_BINDING_U is assumed.
*/
#ifdef DOXYGEN
/**
* @brief UDP binding
*/
#define CONFIG_LWM2M_DEVICE_BINDING_U
/**
* @brief UDP binding with Queue mode
*/
#define CONFIG_LWM2M_DEVICE_BINDING_UQ
/**
* @brief SMS binding
*/
#define CONFIG_LWM2M_DEVICE_BINDING_S
/**
* @brief SMS binding with Queue mode
*/
#define CONFIG_LWM2M_DEVICE_BINDING_SQ
/**
* @brief UDP and SMS bindings
*/
#define CONFIG_LWM2M_DEVICE_BINDING_US
/**
* @brief UDP and SMS bindings with Queue mode
*/
#define CONFIG_LWM2M_DEVICE_BINDING_UQS
#endif
/** @} */
/**
* @brief Device object device type
*/
#ifndef CONFIG_LWM2M_DEVICE_TYPE
#define CONFIG_LWM2M_DEVICE_TYPE "RIOT device"
#endif
/**
* @brief Device object hardware version
*
* @note Defaults to the board name
*/
#ifndef CONFIG_LWM2M_DEVICE_HW_VERSION
#define CONFIG_LWM2M_DEVICE_HW_VERSION RIOT_BOARD
#endif
/**
* @brief Device object software version
*
* @note Defaults to the running RIOT version
*/
#ifndef CONFIG_LWM2M_DEVICE_SW_VERSION
#define CONFIG_LWM2M_DEVICE_SW_VERSION RIOT_VERSION
#endif
/**
* @brief Device binding and queue mode
*
* @note Select using CONFIG_LWM2M_DEVICE_BINDING_*
*/
#if defined(CONFIG_LWM2M_DEVICE_BINDING_U)
#define CONFIG_LWM2M_DEVICE_BINDINGS "U"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_UQ)
#define CONFIG_LWM2M_DEVICE_BINDINGS "UQ"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_S)
#define CONFIG_LWM2M_DEVICE_BINDINGS "S"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_SQ)
#define CONFIG_LWM2M_DEVICE_BINDINGS "SQ"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_US)
#define CONFIG_LWM2M_DEVICE_BINDINGS "US"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_UQS)
#define CONFIG_LWM2M_DEVICE_BINDINGS "UQS"
#else
#define CONFIG_LWM2M_DEVICE_BINDINGS "U"
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -58,13 +58,14 @@ extern "C" {
* *
* @param[in] conn_list connections list to search * @param[in] conn_list connections list to search
* @param[in] remote remote UDP endpoint to compare to * @param[in] remote remote UDP endpoint to compare to
* @param[in] type type of connection to look for
* *
* @return pointer to the connection in success * @return pointer to the connection in success
* @return NULL otherwise * @return NULL otherwise
*/ */
lwm2m_client_connection_t *lwm2m_client_connection_find( lwm2m_client_connection_t *lwm2m_client_connection_find(lwm2m_client_connection_t *conn_list,
lwm2m_client_connection_t *conn_list, const sock_udp_ep_t *remote,
const sock_udp_ep_t *remote); lwm2m_client_connection_type_t type);
/** /**
* @brief Handles a received packet from a connection * @brief Handles a received packet from a connection

View File

@ -40,40 +40,18 @@ extern "C" {
#define LWM2M_ACC_CTRL_CREATE (1 << 4) /**< Creation access */ #define LWM2M_ACC_CTRL_CREATE (1 << 4) /**< Creation access */
/** @} */ /** @} */
/**
* @brief Creates a LwM2M security object with the default configuration from
* net/lwm2m.h
*
* @param[in, out] client_data Pointer to a LwM2M client data descriptor
*
* @return Pointer to the created object in success
* @return NULL otherwise
*/
lwm2m_object_t *lwm2m_client_get_security_object(
lwm2m_client_data_t *client_data);
/** /**
* @brief Creates a LwM2M server object with the default configuration from * @brief Creates a LwM2M server object with the default configuration from
* net/lwm2m.h * net/lwm2m.h
* *
* @param[in, out] client_data Pointer to a LwM2M client data descriptor * @param[in, out] client_data Pointer to a LwM2M client data descriptor
* @param[in] server_id Server ID (SID) to assign to the new instance
* *
* @return Pointer to the created object * @return Pointer to the created object
* @return NULL otherwise * @return NULL otherwise
*/ */
lwm2m_object_t *lwm2m_client_get_server_object( lwm2m_object_t *lwm2m_client_get_server_object(
lwm2m_client_data_t *client_data); lwm2m_client_data_t *client_data, int server_id);
/**
* @brief Creates a LwM2M device object with the default configuration from
* net/lwm2m.h
* @param[in, out] client_data Pointer to a LwM2M client data descriptor
*
* @return Pointer to the created object
* @return NULL otherwise
*/
lwm2m_object_t *lwm2m_client_get_device_object(
lwm2m_client_data_t *client_data);
/** /**
* @brief Creates a LwM2M access control object with the default configuration * @brief Creates a LwM2M access control object with the default configuration

View File

@ -10,6 +10,33 @@
* @ingroup lwm2m_objects * @ingroup lwm2m_objects
* @defgroup lwm2m_objects_device Device LwM2M object * @defgroup lwm2m_objects_device Device LwM2M object
* @brief Device object implementation for LwM2M client using Wakaama * @brief Device object implementation for LwM2M client using Wakaama
*
* | Name | ID | Mandatory | Type | Range | Units | Implemented |
* |-----------------------------|:--:|:---------:|:-------:|:-----:|:-----:|:-----------:|
* | Manufacturer | 0 | No | String | - | - | Yes |
* | Model Number | 1 | No | String | - | - | Yes |
* | Serial Number | 2 | No | String | - | - | Yes |
* | Firmware Version | 3 | No | String | - | - | Yes |
* | Reboot | 4 | Yes | - | - | - | Yes |
* | Factory Reset | 5 | No | - | - | - | No |
* | Available Power Sources | 6 | No | Integer | 0-7 | - | No |
* | Power Source Voltage | 7 | No | Integer | - | mV | No |
* | Power Source Current | 8 | No | Integer | - | mA | No |
* | Battery Level | 9 | No | Integer | 0-100 | % | No |
* | Memory Free | 10 | No | Integer | - | KB | No |
* | Error Code | 11 | Yes | Integer | 0-8 | - | No |
* | Reset Error Code | 12 | No | - | - | - | No |
* | Current Time | 13 | No | Time | - | - | No |
* | UTC Offset | 14 | No | String | - | - | No |
* | Timezone | 15 | No | String | - | - | No |
* | Supported Binding and Modes | 16 | Yes | String | - | - | Yes |
* | Device Type | 17 | No | String | - | - | Yes |
* | Hardware Version | 18 | No | String | - | - | Yes |
* | Software Version | 19 | No | String | - | - | Yes |
* | Battery Status | 20 | No | Integer | 0-6 | - | No |
* | Memory Total | 21 | No | Integer | - | - | No |
* | ExtDevInfo | 22 | No | Objlnk | - | - | No |
*
* @{ * @{
* *
* @file * @file
@ -29,6 +56,7 @@ extern "C" {
#include <string.h> #include <string.h>
#include "liblwm2m.h" #include "liblwm2m.h"
#include "lwm2m_client.h"
#include "lwm2m_client_config.h" #include "lwm2m_client_config.h"
/** /**
@ -81,11 +109,153 @@ enum lwm2m_device_error_codes {
}; };
/** /**
* @brief Frees the memory of @p obj device object * @defgroup lwm2m_objects_device_config LwM2M Device Object configuration
* @ingroup lwm2m_client_config
* *
* @param[in] obj pointer to the device object * @brief Configuration options for the LwM2M Device Object.
* @{
*/ */
void lwm2m_free_object_device(lwm2m_object_t *obj); /**
* @brief Device name used to register at the LwM2M server
*/
#ifndef CONFIG_LWM2M_DEVICE_NAME
#define CONFIG_LWM2M_DEVICE_NAME "testRIOTDevice"
#endif
/**
* @brief Device object manufacturer string
*/
#ifndef CONFIG_LWM2M_DEVICE_MANUFACTURER
#define CONFIG_LWM2M_DEVICE_MANUFACTURER "A RIOT maker"
#endif
/**
* @brief Device object model.
*
* @note Defaults to the board name
*/
#ifndef CONFIG_LWM2M_DEVICE_MODEL
#define CONFIG_LWM2M_DEVICE_MODEL RIOT_BOARD
#endif
/**
* @brief Device object serial number
*/
#ifndef CONFIG_LWM2M_DEVICE_SERIAL
#define CONFIG_LWM2M_DEVICE_SERIAL "undefined"
#endif
/**
* @brief Device object firmware version
*
* @note Defaults to the running RIOT version
*/
#ifndef CONFIG_LWM2M_DEVICE_FW_VERSION
#define CONFIG_LWM2M_DEVICE_FW_VERSION RIOT_VERSION
#endif
/**
* @{
* @name Device bindings and queue modes
*
* This options are meant to be set either via Kconfig or CFLAGS:
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk}
* CFLAGS += -DCONFIG_LWM2M_DEVICE_BINDING_UQ
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* @note Only one option should be selected. If more than one is defined the
* priority follows this order. By default
* @ref CONFIG_LWM2M_DEVICE_BINDING_U is assumed.
*/
#ifdef DOXYGEN
/**
* @brief UDP binding
*/
#define CONFIG_LWM2M_DEVICE_BINDING_U
/**
* @brief UDP binding with Queue mode
*/
#define CONFIG_LWM2M_DEVICE_BINDING_UQ
/**
* @brief SMS binding
*/
#define CONFIG_LWM2M_DEVICE_BINDING_S
/**
* @brief SMS binding with Queue mode
*/
#define CONFIG_LWM2M_DEVICE_BINDING_SQ
/**
* @brief UDP and SMS bindings
*/
#define CONFIG_LWM2M_DEVICE_BINDING_US
/**
* @brief UDP and SMS bindings with Queue mode
*/
#define CONFIG_LWM2M_DEVICE_BINDING_UQS
#endif
/** @} */
/**
* @brief Device object device type
*/
#ifndef CONFIG_LWM2M_DEVICE_TYPE
#define CONFIG_LWM2M_DEVICE_TYPE "RIOT device"
#endif
/**
* @brief Device object hardware version
*
* @note Defaults to the board name
*/
#ifndef CONFIG_LWM2M_DEVICE_HW_VERSION
#define CONFIG_LWM2M_DEVICE_HW_VERSION RIOT_BOARD
#endif
/**
* @brief Device object software version
*
* @note Defaults to the running RIOT version
*/
#ifndef CONFIG_LWM2M_DEVICE_SW_VERSION
#define CONFIG_LWM2M_DEVICE_SW_VERSION RIOT_VERSION
#endif
/** @} */
/**
* @brief Device binding and queue mode
*
* @note Select using CONFIG_LWM2M_DEVICE_BINDING_*
*/
#if defined(CONFIG_LWM2M_DEVICE_BINDING_U)
#define CONFIG_LWM2M_DEVICE_BINDINGS "U"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_UQ)
#define CONFIG_LWM2M_DEVICE_BINDINGS "UQ"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_S)
#define CONFIG_LWM2M_DEVICE_BINDINGS "S"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_SQ)
#define CONFIG_LWM2M_DEVICE_BINDINGS "SQ"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_US)
#define CONFIG_LWM2M_DEVICE_BINDINGS "US"
#elif defined(CONFIG_LWM2M_DEVICE_BINDING_UQS)
#define CONFIG_LWM2M_DEVICE_BINDINGS "UQS"
#else
#define CONFIG_LWM2M_DEVICE_BINDINGS "U"
#endif
/**
* @brief Initialize the Device object.
*
* @param[in] client_data LwM2M client data.
*
* @return Pointer to the Device object on success
*/
lwm2m_object_t *lwm2m_object_device_init(lwm2m_client_data_t *client_data);
/** /**
* @brief Determines if a reboot request has been issued to the device by a * @brief Determines if a reboot request has been issued to the device by a

View File

@ -0,0 +1,433 @@
/*
* Copyright (C) 2021 HAW Hamburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup lwm2m_objects
* @defgroup lwm2m_objects_security Security LwM2M object
* @brief Security object implementation for LwM2M client using Wakaama
*
* @experimental This API is considered experimental and may change in future releases without
* deprecation process.
*
* This implements the LwM2M Security object as specified in the Appendix E1 of
* the LwM2M specification.
*
* So far only NO_SEC, PSK (Pre-shared key) and RPK (Raw public key) modes are available.
*
* ## Resources
*
* For an XML description of the object see
* https://raw.githubusercontent.com/OpenMobileAlliance/lwm2m-registry/prod/version_history/0-1_0.xml.
*
* | Name | ID | Mandatory | Type | Range | Units | Implemented |
* | ----------------------- | -- | --------- | ------- | ------- | ----- | ---------- |
* | Server URI | 0 | Yes | String | | | Yes |
* | Bootstrap Server | 1 | Yes | Boolean | | | Yes |
* | Security Mode | 2 | Yes | Integer | 0-3 | | Yes |
* | Public Key or ID | 3 | Yes | Opaque | | | Yes |
* | Server Public Key | 4 | Yes | Opaque | | | Yes |
* | Secret Key | 5 | Yes | Opaque | | | Yes |
* | SMS Security Mode | 6 | No | Integer | 0-255 | | No |
* | SMS Binding Key Param. | 7 | No | Opaque | 6 B | | No |
* | SMS Binding Secret Keys | 8 | No | Opaque | 32-48 B | | No |
* | Server SMS Number | 9 | No | String | | | No |
* | Short Server ID | 10 | No | Integer | 1-65535 | | Yes |
* | Client Hold Off Time | 11 | No | Integer | | s | Yes |
* | BS Account Timeout | 12 | No | Integer | | s | Yes |
*
* ## Usage
*
* ### Pre-shared keys
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* // assuming buffers psk_id and psk_key containing credential information
* // assuming client_data is a valid lwm2m_client_data_t instance
* // [...]
*
* // prepare instance arguments
* lwm2m_obj_security_args_t args = {
* .server_id = CONFIG_LWM2M_SERVER_SHORT_ID,
* .server_uri = CONFIG_LWM2M_SERVER_URI,
* .security_mode = LWM2M_SECURITY_MODE_PRE_SHARED_KEY,
* .pub_key_or_id = psk_id,
* .pub_key_or_id_len = sizeof(psk_id) - 1,
* .secret_key = psk_key,
* .secret_key_len = sizeof(psk_key) - 1,
* .is_bootstrap = false,
* .client_hold_off_time = 5,
* .bootstrap_account_timeout = 0
* };
*
* // initialize the security object and get handle
* lwm2m_object_t *sec_obj = lwm2m_object_security_init(&client_data);
*
* // instantiate a new security object with instance ID 1
* int res = lwm2m_object_security_instance_create(&args, 1);
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* ### Raw public keys
*
* To use this security mode the following keys are required:
* - server public key (`SubjectPublicKeyInfo` DER encoded, according to RFC5280)
* - own public (`SubjectPublicKeyInfo` DER encoded) and private (as a `ECPrivateKey` DER encoded
* sequence, according to RFC5915)keys. See below on how they can be generated.
*
* It is possible that you may need to increase @ref CONFIG_DTLS_HANDSHAKE_BUFSIZE_EXP when using
* RPK mode.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.c}
* // assuming buffers rpk_pub, rpk_priv, and server_rpk_pub containing the elliptic curve keys
* // assuming client_data is a valid lwm2m_client_data_t instance
* // [...]
*
* // prepare instance arguments
* lwm2m_obj_security_args_t args = {
* .server_id = CONFIG_LWM2M_SERVER_SHORT_ID,
* .server_uri = CONFIG_LWM2M_SERVER_URI,
* .security_mode = LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY,
* .pub_key_or_id = rpk_pub,
* .pub_key_or_id_len = sizeof(rpk_pub),
* .secret_key = rpk_priv,
* .secret_key_len = sizeof(rpk_priv),
* .server_pub_key = server_rpk_pub,
* .server_pub_key_len = sizeof(server_rpk_pub),
* .is_bootstrap = false,
* .client_hold_off_time = 5,
* .bootstrap_account_timeout = 0
* };
*
* // initialize the security object and get handle
* lwm2m_object_t *sec_obj = lwm2m_object_security_init(&client_data);
*
* // instantiate a new security object with next available instance ID
* int id = lwm2m_object_security_instance_create(&args, -1);
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* #### Generating the keys
*
* The local key pair can be generated using [OpenSSL](https://www.openssl.org/).
* 1. Generate the key pair using the secp256r1 parameters:
* ~~~~~~~~~~~~~~~~~~~~
* $ openssl ecparam -name secp256r1 -genkey -outform der -out keys.der
* ~~~~~~~~~~~~~~~~~~~~
*
* 2. Get the public part of the key:
* ~~~~~~~~~~~~~~~~~~~~
* $ openssl ec -in keys.der -inform DER -outform DER -pubout | xxd -i
* ~~~~~~~~~~~~~~~~~~~~
*
* 3. Get the private part of the key:
* ~~~~~~~~~~~~~~~~~~~~
* $ openssl ec -in keys.der -inform DER -no_public -outform DER | xxd -i
* ~~~~~~~~~~~~~~~~~~~~
*
* 4. If your server requires your public key as X-Y coordinates you can dump it as text, remove the
* first byte and split the rest in two equally-sized parts. The first part will be X, the
* second Y.
* ~~~~~~~~~~~~~~~~~~~~
* $ openssl ec -in keys.der -inform DER -text
*
* [...]
* pub:
* 04:a0:c3:8e:cb:a1:02:eb:5d:25:96:98:bb:60:8e:
* 28:19:56:06:96:70:15:9b:54:ff:d9:60:32:c3:3e:
* 89:08:ae:3a:33:2f:54:5f:68:a2:ac:d1:b9:df:2b:
* 79:65:49:3f:1c:ae:64:7a:32:02:e4:32:8d:6b:22:
* 67:83:0d:7c:b2
* ASN1 OID: prime256v1
* NIST CURVE: P-256
* [...]
* ~~~~~~~~~~~~~~~~~~~~
*
* Following the example above we have:
* ~~~~~~~~~~~~~~~~~~~~
* X : a0c38ecba102eb5d259698bb608e281956069670159b54ffd96032c33e8908ae
* Y : 3a332f545f68a2acd1b9df2b7965493f1cae647a3202e4328d6b2267830d7cb2
* ~~~~~~~~~~~~~~~~~~~~
* @{
*
* @file
*
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
*/
#ifndef OBJECTS_SECURITY_H
#define OBJECTS_SECURITY_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "liblwm2m.h"
#include "net/credman.h"
#include "lwm2m_client.h"
#include "lwm2m_client_config.h"
/* these are defined in liblwm2m.h, and are reproduced here for documentation purposes */
#ifdef DOXYGEN
/**
* @name LwM2M Security object security modes
* @{
*/
/**
* @brief Pre-Shared keys mode
*/
#define LWM2M_SECURITY_MODE_PRE_SHARED_KEY 0
/**
* @brief Raw public keys mode
*/
#define LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY 1
/**
* @brief Certificate mode
*/
#define LWM2M_SECURITY_MODE_CERTIFICATE 2
/**
* @brief No security mode
*/
#define LWM2M_SECURITY_MODE_NONE 3
/** @} */
/**
* @name Resource IDs for the LWM2M Security Object
* @{
*/
/**
* @brief Server URI
*/
#define LWM2M_SECURITY_URI_ID 0
/**
* @brief Bootstrap server
*/
#define LWM2M_SECURITY_BOOTSTRAP_ID 1
/**
* @brief Security mode
*/
#define LWM2M_SECURITY_SECURITY_ID 2
/**
* @brief Public key or ID
*/
#define LWM2M_SECURITY_PUBLIC_KEY_ID 3
/**
* @brief Server public key
*/
#define LWM2M_SECURITY_SERVER_PUBLIC_KEY_ID 4
/**
* @brief Secret key
*/
#define LWM2M_SECURITY_SECRET_KEY_ID 5
/**
* @brief SMS security mode
*/
#define LWM2M_SECURITY_SMS_SECURITY_ID 6
/**
* @brief SMS binding key parameters
*/
#define LWM2M_SECURITY_SMS_KEY_PARAM_ID 7
/**
* @brief SMS binding secret keys
*/
#define LWM2M_SECURITY_SMS_SECRET_KEY_ID 8
/**
* @brief Server SMS number
*/
#define LWM2M_SECURITY_SMS_SERVER_NUMBER_ID 9
/**
* @brief Short server ID
*/
#define LWM2M_SECURITY_SHORT_SERVER_ID 10
/**
* @brief Client hold-off time
*/
#define LWM2M_SECURITY_HOLD_OFF_ID 11
/**
* @brief Bootstrap server account timeout
*/
#define LWM2M_SECURITY_BOOTSTRAP_TIMEOUT_ID 12
/** @} */
#endif /* DOXYGEN */
/**
* @defgroup lwm2m_objects_security_config LwM2M Security object compile configurations
* @ingroup lwm2m_client_config
* @{
*/
/**
* @brief Maximum number of instances of the Security object
*/
#ifndef CONFIG_LWM2M_OBJ_SECURITY_INSTANCES_MAX
#define CONFIG_LWM2M_OBJ_SECURITY_INSTANCES_MAX (2)
#endif
/**
* @brief Buffer size of the public key or ID resource
*/
#ifndef CONFIG_LWM2M_OBJ_SECURITY_PUB_KEY_ID_BUFSIZE
#define CONFIG_LWM2M_OBJ_SECURITY_PUB_KEY_ID_BUFSIZE (128)
#endif
/**
* @brief Buffer size of the server public key resource
*/
#ifndef CONFIG_LWM2M_OBJ_SECURITY_SERVER_PUB_KEY_BUFSIZE
#define CONFIG_LWM2M_OBJ_SECURITY_SERVER_PUB_KEY_BUFSIZE (128)
#endif
/**
* @brief Buffer size of the secret key resource
*/
#ifndef CONFIG_LWM2M_OBJ_SECURITY_SEC_KEY_BUFSIZE
#define CONFIG_LWM2M_OBJ_SECURITY_SEC_KEY_BUFSIZE (64)
#endif
/** @} */
/**
* @brief Arguments for a new Security object instance creation
* (@ref lwm2m_object_security_instance_create).
*/
typedef struct lwm2m_obj_security_args {
/**
* @brief Server's short ID the instance is associated to.
*/
uint16_t server_id;
/**
* @brief Server's URI the instance is associated to.
*
* @note This buffer will be copied internally.
*/
const char *server_uri;
/**
* @brief Security mode to use. For now only @ref LWM2M_SECURITY_MODE_NONE and
* @ref LWM2M_SECURITY_MODE_PRE_SHARED_KEY and
* @ref LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY are supported.
*/
uint8_t security_mode;
/**
* @brief Pointer to the Key ID when using @ref LWM2M_SECURITY_MODE_PRE_SHARED_KEY.
* Pointer to the public key encoded as a `SubjectPublicKeyInfo` sequence when using
* @ref LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY (see @ref credman_load_public_key).
* May be `NULL` when @ref LWM2M_SECURITY_MODE_NONE is used.
*
* @note This buffer will be copied internally.
*/
const uint8_t *pub_key_or_id;
/**
* @brief Length of @ref lwm2m_obj_security_args_t::pub_key_or_id.
*/
size_t pub_key_or_id_len;
/**
* @brief Pointer to the Key when using @ref LWM2M_SECURITY_MODE_PRE_SHARED_KEY.
* Pointer to the private key PKCS8 DER encoded when using
* @ref LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY (see @ref credman_load_private_key).
* May be `NULL` when @ref LWM2M_SECURITY_MODE_NONE is used.
*
* @note This buffer will be copied internally.
*/
const uint8_t *secret_key;
/**
* @brief Length of @ref lwm2m_obj_security_args_t::secret_key.
*/
size_t secret_key_len;
/**
* @brief Pointer to the server public key encoded as a `SubjectPublicKeyInfo` sequence when
* using @ref LWM2M_SECURITY_MODE_RAW_PUBLIC_KEY (see @ref credman_load_public_key).
* May be `NULL` when @ref LWM2M_SECURITY_MODE_NONE or
* @ref LWM2M_SECURITY_MODE_PRE_SHARED_KEY are used.
*
* @note This buffer will be copied internally.
*/
const uint8_t *server_pub_key;
/**
* @brief Length of @ref lwm2m_obj_security_args_t::server_pub_key.
*/
size_t server_pub_key_len;
/**
* @brief When `true` the security instance is associated to the Bootstrap-Server.
*/
bool is_bootstrap;
/**
* @brief Time, in seconds, to wait before initiating a 'Client Initiated Bootstrap', after it
* has been determined that it should be initiated.
*/
uint32_t client_hold_off_time;
/**
* @brief Time, in seconds, that the client waits before it purges the Bootstrap-Server's
* account. 0 means never.
*/
uint32_t bootstrap_account_timeout;
} lwm2m_obj_security_args_t;
/**
* @brief Initialize the Security object.
*
* @param[in] client_data LwM2M client data.
*
* @return Pointer to the Security object on success
*/
lwm2m_object_t *lwm2m_object_security_init(lwm2m_client_data_t *client_data);
/**
* @brief Create a new Security instance and add it to the @p object list.
*
* @param[in] args Initialize structure with the parameter for the instance. May
* not be NULL.
* @param[in] instance_id ID for the new instance. It must be between 0 and
* (UINT16_MAX - 1), if -1 the next available ID will be used.
*
* @return Instance ID (> 0) on success
* @return -EINVAL if an invalid @p instance_id is given
* @return -ENOMEM if no memory is available to create a new instance
*/
int lwm2m_object_security_instance_create(const lwm2m_obj_security_args_t *args,
int32_t instance_id);
/**
* @brief Get the credential of a given instance of the security object.
*
* @param[in] instance_id ID of the instance.
*
* @return Credential tag.
* @retval CREDMAN_TAG_EMPTY when no credential is assigned.
*/
credman_tag_t lwm2m_object_security_get_credential(uint16_t instance_id);
#ifdef __cplusplus
}
#endif
#endif /* OBJECTS_SECURITY_H */
/** @} */

View File

@ -2,7 +2,6 @@ MODULE = wakaama_client
SRC = \ SRC = \
object_server.c \ object_server.c \
object_security.c \
object_access_control.c \ object_access_control.c \
# #