mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Merge pull request #16233 from leandrolanzieri/pr/pkg/wakaama_dtls
pkg/wakaama: add DTLS support
This commit is contained in:
commit
67f183d6a9
44
examples/lwm2m/Kconfig
Normal file
44
examples/lwm2m/Kconfig
Normal 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
|
@ -1,5 +1,5 @@
|
||||
# name of your application
|
||||
APPLICATION = wakaama
|
||||
APPLICATION = lwm2m
|
||||
|
||||
# If no BOARD is found in the environment, use this default:
|
||||
BOARD ?= native
|
||||
@ -7,8 +7,6 @@ BOARD ?= native
|
||||
# This has to be the absolute path to the RIOT base directory:
|
||||
RIOTBASE ?= $(CURDIR)/../..
|
||||
|
||||
|
||||
|
||||
# Include packages that pull up and auto-init the link layer.
|
||||
# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present
|
||||
USEMODULE += netdev_default
|
||||
@ -27,21 +25,34 @@ USEMODULE += ps
|
||||
# development process:
|
||||
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
|
||||
USEPKG += wakaama
|
||||
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
|
||||
# CFLAGS += -DCONFIG_LWM2M_BOOTSTRAP=1
|
||||
# add DTLS support
|
||||
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
|
||||
|
||||
# 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
|
||||
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
|
||||
|
@ -1,5 +1,6 @@
|
||||
BOARD_INSUFFICIENT_MEMORY := \
|
||||
airfy-beacon \
|
||||
arduino-mkr1000 \
|
||||
b-l072z-lrwan1 \
|
||||
blackpill-stm32f103c8 \
|
||||
blackpill-stm32f103cb \
|
||||
@ -7,8 +8,13 @@ BOARD_INSUFFICIENT_MEMORY := \
|
||||
bluepill-stm32f103c8 \
|
||||
bluepill-stm32f103cb \
|
||||
calliope-mini \
|
||||
cc1350-launchpad \
|
||||
cc2650-launchpad \
|
||||
cc2650stk \
|
||||
e104-bt5010a-tb \
|
||||
e104-bt5011a-tb \
|
||||
feather-m0-wifi \
|
||||
gd32vf103c-start \
|
||||
hifive1 \
|
||||
hifive1b \
|
||||
i-nucleo-lrwan1 \
|
||||
@ -24,16 +30,23 @@ BOARD_INSUFFICIENT_MEMORY := \
|
||||
nucleo-f042k6 \
|
||||
nucleo-f070rb \
|
||||
nucleo-f072rb \
|
||||
nucleo-f103rb \
|
||||
nucleo-f302r8 \
|
||||
nucleo-f303k8 \
|
||||
nucleo-f334r8 \
|
||||
nucleo-l011k4 \
|
||||
nucleo-l031k6 \
|
||||
nucleo-l053r8 \
|
||||
nucleo-l073rz \
|
||||
olimexino-stm32 \
|
||||
opencm904 \
|
||||
openmote-b \
|
||||
samd10-xmini \
|
||||
saml10-xpro \
|
||||
saml11-xpro \
|
||||
seeedstudio-gd32 \
|
||||
sipeed-longan-nano \
|
||||
sipeed-longan-nano-tft \
|
||||
slstk3400a \
|
||||
spark-core \
|
||||
stk3200 \
|
||||
|
@ -41,12 +41,19 @@ Router, you might want to specify:
|
||||
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
|
||||
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.
|
||||
|
||||
By default the bootstrap server option is disabled, it can be enabled by defining
|
||||
`CONFIG_LWM2M_BOOTSTRAP` as 1 (see the Makefile in this application).
|
||||
By default the security instance created in the application assumes that a standard LwM2M Server is
|
||||
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
|
||||
from the ones of previous server (default are 5683 for CoAP, 5684 for CoAPs,
|
||||
@ -66,34 +73,34 @@ BS_COAPSPORT=5686
|
||||
BS_WEBPORT=8888
|
||||
|
||||
# run the server
|
||||
java -jar ./leshan-bsserver-demo.jar --coapport ${BS_COAPPORT} \
|
||||
--coapsport ${BS_COAPSPORT} --webport ${BS_WEBPORT}
|
||||
java -jar ./leshan-bsserver-demo.jar --coap-port ${BS_COAPPORT} \
|
||||
--coaps-port ${BS_COAPSPORT} --web-port ${BS_WEBPORT}
|
||||
```
|
||||
|
||||
To set up the configuration of the node and the server:
|
||||
1. Click the `Add new client bootstrap configuration` button.
|
||||
2. Fill in the name of the device, it **should** match the one set in
|
||||
`lwm2m.h` as `CONFIG_LWM2M_DEVICE_NAME`.
|
||||
2. Fill in the name of the device, it **should** match the one set as `CONFIG_LWM2M_DEVICE_NAME`,
|
||||
in `objects/device.h`.
|
||||
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
|
||||
The address set as `CONFIG_LWM2M_SERVER_URI` (in `lwm2m.h` or via `menuconfig`)
|
||||
should be reachable from the node, e.g. either running on native with a tap
|
||||
interface or as a mote connected to a
|
||||
The server address is set by the application, during the instantiation of the Security object.
|
||||
It can be set via `menuconfig` or the environmental variable `LWM2M_SERVER_URI`. It should be
|
||||
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).
|
||||
|
||||
Also, if a bootstrap server is being used the macro `CONFIG_LWM2M_BOOTSTRAP` should be
|
||||
defined as 1.
|
||||
|
||||
The server URI for the example is being defined using the variable `SERVER_URI`
|
||||
in the Makefile, and can be changed when compiling.
|
||||
Also, if a bootstrap server is being used, it should be configured in the application via
|
||||
`menuconfig` or setting the environmental variable `LWM2M_SERVER_BOOTSTRAP` to 1. This information
|
||||
is used in the Security object instance.
|
||||
|
||||
#### Configure, compile and run
|
||||
|
||||
The Wakaama package can be configured via Kconfig. Its options are placed
|
||||
under `Packages > Configure Wakaama LwM2M`. To access the configuration
|
||||
interface you can run:
|
||||
under `Packages > Configure Wakaama LwM2M`. There is also an application-specific configuration
|
||||
menu. There the Server URI and credentials can be set. To access the configuration interface you
|
||||
can run:
|
||||
```
|
||||
make menuconfig
|
||||
```
|
||||
|
2
examples/lwm2m/app.config
Normal file
2
examples/lwm2m/app.config
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_DTLS_PEER_MAX=2
|
||||
CONFIG_DTLS_HANDSHAKE_BUFSIZE_EXP=9
|
79
examples/lwm2m/credentials.h
Normal file
79
examples/lwm2m/credentials.h
Normal 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 */
|
@ -21,8 +21,13 @@
|
||||
#include "lwm2m_client.h"
|
||||
#include "lwm2m_client_objects.h"
|
||||
#include "lwm2m_platform.h"
|
||||
#include "objects/light_control.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_APP_TYPE "LED 0"
|
||||
@ -58,12 +63,13 @@ void lwm2m_cli_init(void)
|
||||
lwm2m_client_init(&client_data);
|
||||
|
||||
/* add objects that will be registered */
|
||||
obj_list[0] = lwm2m_client_get_security_object(&client_data);
|
||||
obj_list[1] = lwm2m_client_get_server_object(&client_data);
|
||||
obj_list[2] = lwm2m_client_get_device_object(&client_data);
|
||||
obj_list[0] = lwm2m_object_security_init(&client_data);
|
||||
obj_list[1] = lwm2m_client_get_server_object(&client_data, CONFIG_LWM2M_SERVER_SHORT_ID);
|
||||
obj_list[2] = lwm2m_object_device_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_arg = NULL,
|
||||
.color = LED_COLOR,
|
||||
@ -72,12 +78,54 @@ void lwm2m_cli_init(void)
|
||||
.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) {
|
||||
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]) {
|
||||
puts("Could not create mandatory objects");
|
||||
}
|
||||
@ -119,7 +167,7 @@ int lwm2m_cli_cmd(int argc, char **argv)
|
||||
|
||||
if (!strcmp(argv[1], "start")) {
|
||||
/* 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;
|
||||
}
|
||||
return 0;
|
||||
|
@ -7,19 +7,12 @@
|
||||
menu "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
|
||||
bool "TLS_PSK_WITH_AES_128_CCM_8"
|
||||
|
||||
config DTLS_ECC
|
||||
bool "TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8"
|
||||
|
||||
endchoice
|
||||
|
||||
config DTLS_DEBUG
|
||||
bool "Enable debug log"
|
||||
help
|
||||
|
@ -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
|
||||
# General Public License v2.1. See the file LICENSE in the top level
|
||||
@ -10,96 +10,15 @@ menu "Wakaama LwM2M"
|
||||
menu "Remote server"
|
||||
|
||||
config LWM2M_STANDARD_PORT
|
||||
string "CoAP default port of the LwM2M server"
|
||||
string "CoAP default port of a LwM2M server"
|
||||
default "5683"
|
||||
|
||||
config LWM2M_DTLS_PORT
|
||||
string "CoAPS default port of the LwM2M server"
|
||||
string "CoAPS default port of a LwM2M server"
|
||||
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
|
||||
|
||||
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
|
||||
int "Lifetime of the device"
|
||||
default 300
|
||||
@ -107,9 +26,13 @@ config LWM2M_DEVICE_TTL
|
||||
Lifetime of the device on the LwM2M server, expressed in seconds.
|
||||
|
||||
config LWM2M_LOCAL_PORT
|
||||
string "Default port for the local LwM2M instance"
|
||||
string "Port for the local LwM2M CoAP"
|
||||
default "5683"
|
||||
|
||||
config LWM2M_LOCAL_DTLS_PORT
|
||||
string "Port for the local LwM2M CoAPs server"
|
||||
default "5684"
|
||||
|
||||
config LWM2M_ALT_PATH
|
||||
string "Alternate path to place LwM2M resources"
|
||||
default "/"
|
||||
@ -121,6 +44,22 @@ config LWM2M_TLSF_BUFFER
|
||||
int "Allocation buffer size"
|
||||
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"
|
||||
|
||||
endmenu # Wakaama LwM2M
|
||||
|
@ -8,8 +8,9 @@ USEMODULE += uri_parser
|
||||
# folder, by adding 'wakaama_objects_<objectName>' modules
|
||||
USEMODULE += wakaama_objects
|
||||
|
||||
# include the 'device' object implementation (mandatory)
|
||||
# include mandatory objects
|
||||
USEMODULE += wakaama_objects_device
|
||||
USEMODULE += wakaama_objects_security
|
||||
|
||||
USEMODULE += ztimer
|
||||
USEMODULE += ztimer_sec
|
||||
@ -22,3 +23,13 @@ endif
|
||||
|
||||
# wakaama uses Sock UDP (implemented by some stack)
|
||||
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
|
||||
|
@ -18,3 +18,4 @@ ifneq (,$(or $(CONFIG_LWM2M_WITH_LOGS),$(filter -DCONFIG_LWM2M_WITH_LOGS=1,$(CFL
|
||||
endif
|
||||
|
||||
PSEUDOMODULES += wakaama
|
||||
PSEUDOMODULES += wakaama_client_dtls
|
||||
|
@ -21,9 +21,17 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "kernel_defines.h"
|
||||
#include "timex.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_client.h"
|
||||
@ -34,26 +42,146 @@
|
||||
#include "debug.h"
|
||||
|
||||
/**
|
||||
* @brief Determines if there has been a reboot request on the device object
|
||||
*
|
||||
* @note This function is implemented in object_device.c
|
||||
*
|
||||
* @return true Reboot has been requested
|
||||
* @return false Reboot has not been requested
|
||||
* @brief Callback for event timeout that performs a step on the LwM2M FSM.
|
||||
*/
|
||||
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
|
||||
* FSM.
|
||||
*
|
||||
* @param arg ignored
|
||||
* @brief Callback to handle UDP sock events.
|
||||
*/
|
||||
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];
|
||||
static lwm2m_client_data_t *_client_data;
|
||||
/**
|
||||
* @brief Handle an incoming packet from a remote peer.
|
||||
*/
|
||||
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)
|
||||
{
|
||||
@ -73,11 +201,36 @@ lwm2m_context_t *lwm2m_client_run(lwm2m_client_data_t *client_data,
|
||||
|
||||
/* create sock for UDP server */
|
||||
_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");
|
||||
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 */
|
||||
_client_data->lwm2m_ctx = lwm2m_init(_client_data);
|
||||
if (!_client_data->lwm2m_ctx) {
|
||||
@ -92,115 +245,200 @@ lwm2m_context_t *lwm2m_client_run(lwm2m_client_data_t *client_data,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_client_data->pid = thread_create(_lwm2m_client_stack,
|
||||
sizeof(_lwm2m_client_stack),
|
||||
THREAD_PRIORITY_MAIN - 1,
|
||||
THREAD_CREATE_STACKTEST,
|
||||
_lwm2m_client_run,
|
||||
NULL,
|
||||
"LwM2M client");
|
||||
#if IS_USED(MODULE_WAKAAMA_CLIENT_DTLS)
|
||||
lwm2m_client_refresh_dtls_credentials();
|
||||
#endif
|
||||
|
||||
sock_udp_event_init(&_client_data->sock, EVENT_PRIO_MEDIUM, _udp_event_handler, NULL);
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
lwm2m_client_connection_t *conn;
|
||||
|
||||
if (lwm2m_device_reboot_requested()) {
|
||||
time_t tv_sec;
|
||||
DEBUG("[lwm2m:client] finding connection\n");
|
||||
conn = lwm2m_client_connection_find(_client_data->conn_list, remote, type);
|
||||
|
||||
tv_sec = lwm2m_gettime();
|
||||
|
||||
if (0 == reboot_time) {
|
||||
DEBUG("reboot requested; rebooting in %u seconds\n",
|
||||
LWM2M_CLIENT_REBOOT_TIME);
|
||||
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);
|
||||
if (conn) {
|
||||
DEBUG("[lwm2m:client] handle packet (%i bytes)\n", (int)len);
|
||||
int result = lwm2m_connection_handle_packet(conn, buffer, len, _client_data);
|
||||
if (0 != result) {
|
||||
DEBUG("[lwm2m:client] error handling message %i\n", result);
|
||||
}
|
||||
}
|
||||
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 */
|
||||
|
@ -39,11 +39,18 @@
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include "kernel_defines.h"
|
||||
#include "net/netif.h"
|
||||
#include "uri_parser.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_config.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
|
||||
*
|
||||
* @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);
|
||||
|
||||
@ -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_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);
|
||||
if (new_conn) {
|
||||
@ -170,9 +177,9 @@ uint8_t lwm2m_buffer_send(void *sessionH, uint8_t *buffer, size_t length,
|
||||
return COAP_NO_ERROR;
|
||||
}
|
||||
|
||||
lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
lwm2m_client_connection_t *conn_list,
|
||||
const sock_udp_ep_t *remote)
|
||||
lwm2m_client_connection_t *lwm2m_client_connection_find(lwm2m_client_connection_t *conn_list,
|
||||
const sock_udp_ep_t *remote,
|
||||
lwm2m_client_connection_type_t type)
|
||||
{
|
||||
lwm2m_client_connection_t *conn = conn_list;
|
||||
|
||||
@ -180,7 +187,7 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
uint8_t ip_len = 128;
|
||||
|
||||
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) {
|
||||
DEBUG("Conn list is null!");
|
||||
@ -188,8 +195,8 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
|
||||
while (conn != NULL) {
|
||||
ipv6_addr_to_str(ip, (ipv6_addr_t *)&conn->remote.addr.ipv6, ip_len);
|
||||
DEBUG("Comparing to [%s]:%d\n", ip, conn->remote.port);
|
||||
if ((conn->remote.port == remote->port) &&
|
||||
DEBUG("Comparing to [%s]:%" PRIu16 "\n", ip, conn->remote.port);
|
||||
if ((conn->remote.port == remote->port) && conn->type == type &&
|
||||
ipv6_addr_equal((ipv6_addr_t *)&(conn->remote.addr.ipv6),
|
||||
(ipv6_addr_t *)&(remote->addr.ipv6))) {
|
||||
break;
|
||||
@ -199,9 +206,8 @@ lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
return conn;
|
||||
}
|
||||
|
||||
int lwm2m_connection_handle_packet(lwm2m_client_connection_t *conn,
|
||||
uint8_t *buffer, size_t num_bytes,
|
||||
lwm2m_client_data_t *client_data)
|
||||
int lwm2m_connection_handle_packet(lwm2m_client_connection_t *conn, uint8_t *buffer,
|
||||
size_t num_bytes, lwm2m_client_data_t *client_data)
|
||||
{
|
||||
lwm2m_handle_packet(client_data->lwm2m_ctx, buffer, num_bytes, conn);
|
||||
return 0;
|
||||
@ -211,12 +217,26 @@ static int _connection_send(lwm2m_client_connection_t *conn, uint8_t *buffer,
|
||||
size_t buffer_size,
|
||||
lwm2m_client_data_t *client_data)
|
||||
{
|
||||
ssize_t sent_bytes = sock_udp_send(&(client_data->sock), buffer,
|
||||
buffer_size, &(conn->remote));
|
||||
if (sent_bytes <= 0) {
|
||||
DEBUG("[_connection_send] Could not send UDP packet: %" PRIiSIZE "\n", sent_bytes);
|
||||
return -1;
|
||||
DEBUG("[_connection_send] trying to send %" PRIiSIZE " bytes\n", buffer_size);
|
||||
if (conn->type == LWM2M_CLIENT_CONN_UDP) {
|
||||
ssize_t sent_bytes = sock_udp_send(&(client_data->sock), buffer,
|
||||
buffer_size, &(conn->remote));
|
||||
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();
|
||||
return 0;
|
||||
}
|
||||
@ -225,7 +245,8 @@ static netif_t *_get_interface(const char *iface, size_t iface_len)
|
||||
{
|
||||
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 */
|
||||
unsigned netif_numof = 0;
|
||||
while ((netif = netif_iter(netif)) != NULL) {
|
||||
@ -240,6 +261,7 @@ static netif_t *_get_interface(const char *iface, size_t iface_len)
|
||||
}
|
||||
}
|
||||
else {
|
||||
DEBUG("[lwm2m:client] getting interface by name %.*s\n", (unsigned)iface_len, iface);
|
||||
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_connection_t *conn = NULL;
|
||||
char uri[MAX_URI_LENGTH];
|
||||
char uri[MAX_URI_LENGTH] = { 0 };
|
||||
size_t uri_len = ARRAY_SIZE(uri);
|
||||
uint16_t port;
|
||||
bool is_bootstrap;
|
||||
@ -299,7 +321,7 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
|
||||
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);
|
||||
|
||||
/* allocate new connection */
|
||||
@ -331,7 +353,9 @@ static lwm2m_client_connection_t *_connection_create(uint16_t sec_obj_inst_id,
|
||||
* is only one defined. */
|
||||
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);
|
||||
|
||||
if (netif == NULL) {
|
||||
DEBUG("[lwm2m:client] could not determine an interface to use\n");
|
||||
goto free_out;
|
||||
}
|
||||
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();
|
||||
goto out;
|
||||
|
||||
|
@ -21,52 +21,24 @@
|
||||
#include "kernel_defines.h"
|
||||
|
||||
#include "lwm2m_client.h"
|
||||
#include "objects/device.h"
|
||||
#include "lwm2m_client_config.h"
|
||||
#include "lwm2m_client_objects.h"
|
||||
|
||||
/* These functions are defined by the objects (object_security.c and
|
||||
* object_server.c are implemented by the Wakaama package. device.c can be
|
||||
* found in '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);
|
||||
/* These functions are defined by the objects (object_server.c is implemented by
|
||||
* the Wakaama package. security.c and device.c can be found in
|
||||
* 'contrib/objects') */
|
||||
lwm2m_object_t *get_server_object(int server_id, const char *binding,
|
||||
int lifetime, bool storing);
|
||||
lwm2m_object_t *lwm2m_get_object_device(void);
|
||||
|
||||
lwm2m_object_t *lwm2m_client_get_security_object(
|
||||
lwm2m_client_data_t *client_data)
|
||||
lwm2m_object_t *lwm2m_client_get_server_object(lwm2m_client_data_t *client_data,
|
||||
int server_id)
|
||||
{
|
||||
(void)client_data;
|
||||
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;
|
||||
|
||||
ret = get_server_object(server_id, CONFIG_LWM2M_DEVICE_BINDINGS, lifetime,
|
||||
false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
lwm2m_object_t *lwm2m_client_get_device_object(
|
||||
lwm2m_client_data_t *client_data)
|
||||
{
|
||||
(void)client_data;
|
||||
return lwm2m_get_object_device();
|
||||
}
|
||||
|
@ -5,4 +5,6 @@
|
||||
# directory for more details.
|
||||
#
|
||||
|
||||
rsource "Kconfig.device"
|
||||
rsource "Kconfig.security"
|
||||
rsource "Kconfig.light_control"
|
||||
|
68
pkg/wakaama/contrib/objects/Kconfig.device
Normal file
68
pkg/wakaama/contrib/objects/Kconfig.device
Normal 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
|
26
pkg/wakaama/contrib/objects/Kconfig.security
Normal file
26
pkg/wakaama/contrib/objects/Kconfig.security
Normal 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
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
* @author Christian Manal <manal@uni-bremen.de>
|
||||
* @author Leandro Lanzieri <leandro.lanzieri@haw-hamburg.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
@ -25,43 +27,90 @@
|
||||
#include "objects/device.h"
|
||||
#include "lwm2m_client_config.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
/* Set to true if reboot requested. */
|
||||
static bool reboot;
|
||||
|
||||
/* Lookup table for static resources of device object */
|
||||
static const char *_static_resources[] = {
|
||||
[LWM2M_RES_MANUFACTURER] = CONFIG_LWM2M_DEVICE_MANUFACTURER,
|
||||
[LWM2M_RES_MODEL_NO] = CONFIG_LWM2M_DEVICE_MODEL,
|
||||
[LWM2M_RES_SERIAL] = CONFIG_LWM2M_DEVICE_SERIAL,
|
||||
[LWM2M_RES_FW_VER] = CONFIG_LWM2M_DEVICE_FW_VERSION,
|
||||
[LWM2M_RES_BINDINGS] = CONFIG_LWM2M_DEVICE_BINDINGS,
|
||||
[LWM2M_RES_TYPE] = CONFIG_LWM2M_DEVICE_TYPE,
|
||||
[LWM2M_RES_HW_VERSION] = CONFIG_LWM2M_DEVICE_HW_VERSION,
|
||||
[LWM2M_RES_SW_VERSION] = CONFIG_LWM2M_DEVICE_SW_VERSION,
|
||||
[LWM2M_DEVICE_RESOURCES] = NULL
|
||||
/**
|
||||
* @brief 'Execute' callback for the Device object.
|
||||
*
|
||||
* @param[in] instance_id Instance ID. Should be 0 as a single instance exists.
|
||||
* @param[in] resource_id ID of the resource to execute.
|
||||
* @param[in] buffer Information needed for the execution.
|
||||
* @param[in] length Length of @p buffer.
|
||||
* @param[in] object Device object pointer
|
||||
*
|
||||
* @return COAP_204_CHANGED on success
|
||||
* @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 */
|
||||
typedef struct {
|
||||
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)
|
||||
static uint8_t _discover_cb(uint16_t instance_id, int *num_data, lwm2m_data_t **data_array,
|
||||
lwm2m_object_t *object)
|
||||
{
|
||||
uint8_t result;
|
||||
int i;
|
||||
|
||||
(void)objectP;
|
||||
(void)object;
|
||||
|
||||
if (instance_id != 0) {
|
||||
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;
|
||||
|
||||
if (*num_dataP == 0) {
|
||||
if (*num_data == 0) {
|
||||
/* This list must contain all available resources */
|
||||
uint16_t res[] = {
|
||||
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);
|
||||
|
||||
*data_arrayP = lwm2m_data_new(len);
|
||||
if (*data_arrayP == NULL) {
|
||||
*data_array = lwm2m_data_new(len);
|
||||
*num_data = len;
|
||||
|
||||
if (*data_array == NULL) {
|
||||
DEBUG("[lwm2m:device:discover] could not allocate data array\n");
|
||||
return COAP_500_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
*num_dataP = len;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
(*data_arrayP)[i].id = res[i];
|
||||
(*data_array)[i].id = res[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Check if each given resource is present */
|
||||
for (i = 0; i < *num_dataP && result == COAP_205_CONTENT; i++) {
|
||||
switch ((*data_arrayP)[i].id) {
|
||||
for (i = 0; i < *num_data && result == COAP_205_CONTENT; i++) {
|
||||
switch ((*data_array)[i].id) {
|
||||
case LWM2M_RES_MANUFACTURER:
|
||||
case LWM2M_RES_MODEL_NO:
|
||||
case LWM2M_RES_SERIAL:
|
||||
@ -114,23 +166,22 @@ static uint8_t prv_device_discover(uint16_t instance_id, int *num_dataP,
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t prv_device_read(uint16_t instance_id, int *num_dataP,
|
||||
lwm2m_data_t **data_arrayP,
|
||||
lwm2m_object_t *objectP)
|
||||
static uint8_t _read_cb(uint16_t instance_id, int *num_data, lwm2m_data_t **data_array,
|
||||
lwm2m_object_t *object)
|
||||
{
|
||||
(void)object;
|
||||
int i;
|
||||
uint8_t result = COAP_404_NOT_FOUND;
|
||||
dev_data_t *data = (dev_data_t *)objectP->userData;
|
||||
|
||||
(void)data;
|
||||
DEBUG("[lwm2m:device:read]\n");
|
||||
|
||||
/* Single instance object */
|
||||
if (instance_id != 0) {
|
||||
goto out;
|
||||
return COAP_404_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
uint16_t resList[] = {
|
||||
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,
|
||||
};
|
||||
int cnt = ARRAY_SIZE(resList);
|
||||
*data_arrayP = lwm2m_data_new(cnt);
|
||||
if (*data_arrayP == NULL) {
|
||||
result = COAP_500_INTERNAL_SERVER_ERROR;
|
||||
goto out;
|
||||
*data_array = lwm2m_data_new(cnt);
|
||||
*num_data = cnt;
|
||||
|
||||
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++) {
|
||||
(*data_arrayP)[i].id = resList[i];
|
||||
(*data_array)[i].id = resList[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < *num_dataP; i++) {
|
||||
switch ((*data_arrayP)[i].id) {
|
||||
/* Exec resources */
|
||||
case LWM2M_RES_REBOOT:
|
||||
case LWM2M_RES_FRESET:
|
||||
case LWM2M_RES_ERROR_CODE_RESET:
|
||||
result = COAP_405_METHOD_NOT_ALLOWED;
|
||||
goto out;
|
||||
break;
|
||||
case LWM2M_RES_ERROR_CODE:
|
||||
/* TODO: Here some error reporting should be implemented. */
|
||||
lwm2m_data_encode_int(LWM2M_DEVICE_ERR_NO_ERR, *data_arrayP + i);
|
||||
result = COAP_205_CONTENT;
|
||||
break;
|
||||
/* The rest are either static or not defined resources */
|
||||
default:
|
||||
if (_static_resources[(*data_arrayP)[i].id]) {
|
||||
lwm2m_data_encode_string(
|
||||
_static_resources[(*data_arrayP)[i].id],
|
||||
*data_arrayP + i);
|
||||
result = COAP_205_CONTENT;
|
||||
}
|
||||
else {
|
||||
result = COAP_404_NOT_FOUND;
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < *num_data; i++) {
|
||||
lwm2m_data_t *data = &(*data_array)[i];
|
||||
|
||||
DEBUG("[lwm2m:device:read] reading resource %d\n", data->id);
|
||||
switch (data->id) {
|
||||
/* Exec resources, can't be read */
|
||||
case LWM2M_RES_REBOOT:
|
||||
case LWM2M_RES_FRESET:
|
||||
case LWM2M_RES_ERROR_CODE_RESET:
|
||||
return COAP_405_METHOD_NOT_ALLOWED;
|
||||
break;
|
||||
|
||||
case LWM2M_RES_ERROR_CODE:
|
||||
/* TODO: Here some error reporting should be implemented. For now returning no error */
|
||||
lwm2m_data_encode_int(LWM2M_DEVICE_ERR_NO_ERR, data);
|
||||
break;
|
||||
|
||||
case LWM2M_RES_MANUFACTURER:
|
||||
lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_MANUFACTURER, data);
|
||||
break;
|
||||
|
||||
case LWM2M_RES_MODEL_NO:
|
||||
lwm2m_data_encode_string(CONFIG_LWM2M_DEVICE_MODEL, data);
|
||||
break;
|
||||
|
||||
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 result;
|
||||
return COAP_205_CONTENT;
|
||||
}
|
||||
|
||||
static uint8_t prv_device_write(uint16_t instance_id, int num_data,
|
||||
lwm2m_data_t *data_array,
|
||||
lwm2m_object_t *objectP)
|
||||
static uint8_t _execute_cb(uint16_t instance_id, uint16_t resource_id, uint8_t *buffer, int length,
|
||||
lwm2m_object_t *object)
|
||||
{
|
||||
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)length;
|
||||
(void)objectP;
|
||||
(void)object;
|
||||
|
||||
/* single instance object */
|
||||
if (instance_id != 0) {
|
||||
result = COAP_404_NOT_FOUND;
|
||||
goto err_out;
|
||||
return COAP_404_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (length != 0) {
|
||||
result = COAP_400_BAD_REQUEST;
|
||||
goto err_out;
|
||||
return COAP_400_BAD_REQUEST;
|
||||
}
|
||||
|
||||
switch (resource_id) {
|
||||
case LWM2M_RES_REBOOT:
|
||||
reboot = true;
|
||||
result = COAP_204_CHANGED;
|
||||
break;
|
||||
case LWM2M_RES_ERROR_CODE_RESET:
|
||||
/* TODO */
|
||||
case LWM2M_RES_FRESET:
|
||||
/* TODO Callback? */
|
||||
default:
|
||||
result = COAP_405_METHOD_NOT_ALLOWED;
|
||||
/* for now only rebooting is available */
|
||||
if (resource_id == LWM2M_RES_REBOOT) {
|
||||
reboot = true;
|
||||
return COAP_204_CHANGED;
|
||||
}
|
||||
|
||||
err_out:
|
||||
return result;
|
||||
return COAP_405_METHOD_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -251,63 +296,10 @@ bool lwm2m_device_reboot_requested(void)
|
||||
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));
|
||||
|
||||
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);
|
||||
_device_object.userData = client_data;
|
||||
return &_device_object;
|
||||
}
|
||||
|
913
pkg/wakaama/contrib/objects/security.c
Normal file
913
pkg/wakaama/contrib/objects/security.c
Normal 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 */
|
||||
}
|
@ -1,7 +1,119 @@
|
||||
/**
|
||||
* @defgroup pkg_wakaama Wakaama LwM2M implementation
|
||||
* @defgroup pkg_wakaama LwM2M - Lightweight Machine to Machine
|
||||
* @ingroup pkg
|
||||
* @ingroup net
|
||||
* @brief Provides the Wakaama implementation of LwM2M
|
||||
* @see https://github.com/eclipse/wakaama
|
||||
*/
|
||||
* @brief LwM2M implementation based on the Wakaama package
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
@ -36,16 +36,32 @@ extern "C" {
|
||||
#include "periph/pm.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 "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
|
||||
*/
|
||||
typedef struct lwm2m_client_connection {
|
||||
struct lwm2m_client_connection *next; /**< pointer to the next connection */
|
||||
sock_udp_ep_t remote; /**< remote endpoint */
|
||||
time_t last_send; /**< last sent packet to the server */
|
||||
sock_udp_ep_t remote; /**< remote endpoint */
|
||||
#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;
|
||||
|
||||
/**
|
||||
@ -54,6 +70,11 @@ typedef struct lwm2m_client_connection {
|
||||
typedef struct {
|
||||
kernel_pid_t pid; /**< PID of the client thread */
|
||||
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 */
|
||||
lwm2m_context_t *lwm2m_ctx; /**< LwM2M context */
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
#endif
|
||||
|
@ -59,10 +59,10 @@ extern "C" {
|
||||
#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
|
||||
#define CONFIG_LWM2M_DEVICE_NAME "testRIOTDevice"
|
||||
#ifndef CONFIG_LWM2M_LOCAL_DTLS_PORT
|
||||
#define CONFIG_LWM2M_LOCAL_DTLS_PORT "5684"
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -72,23 +72,6 @@ extern "C" {
|
||||
#define CONFIG_LWM2M_DEVICE_TTL 300
|
||||
#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
|
||||
*/
|
||||
@ -97,7 +80,7 @@ extern "C" {
|
||||
#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:
|
||||
*
|
||||
@ -110,128 +93,17 @@ extern "C" {
|
||||
#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
|
||||
#define CONFIG_LWM2M_DEVICE_MANUFACTURER "A RIOT maker"
|
||||
#ifndef CONFIG_LWM2M_CREDMAN_TAG_BASE
|
||||
#define CONFIG_LWM2M_CREDMAN_TAG_BASE (10U)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Device object model.
|
||||
*
|
||||
* @note Defaults to the board name
|
||||
* @brief Maximum length of an URI allowed.
|
||||
*/
|
||||
#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"
|
||||
#ifndef CONFIG_LWM2M_URI_MAX_SIZE
|
||||
#define CONFIG_LWM2M_URI_MAX_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -58,13 +58,14 @@ extern "C" {
|
||||
*
|
||||
* @param[in] conn_list connections list to search
|
||||
* @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 NULL otherwise
|
||||
*/
|
||||
lwm2m_client_connection_t *lwm2m_client_connection_find(
|
||||
lwm2m_client_connection_t *conn_list,
|
||||
const sock_udp_ep_t *remote);
|
||||
lwm2m_client_connection_t *lwm2m_client_connection_find(lwm2m_client_connection_t *conn_list,
|
||||
const sock_udp_ep_t *remote,
|
||||
lwm2m_client_connection_type_t type);
|
||||
|
||||
/**
|
||||
* @brief Handles a received packet from a connection
|
||||
|
@ -40,40 +40,18 @@ extern "C" {
|
||||
#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
|
||||
* net/lwm2m.h
|
||||
*
|
||||
* @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 NULL otherwise
|
||||
*/
|
||||
lwm2m_object_t *lwm2m_client_get_server_object(
|
||||
lwm2m_client_data_t *client_data);
|
||||
|
||||
/**
|
||||
* @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);
|
||||
lwm2m_client_data_t *client_data, int server_id);
|
||||
|
||||
/**
|
||||
* @brief Creates a LwM2M access control object with the default configuration
|
||||
|
@ -10,6 +10,33 @@
|
||||
* @ingroup lwm2m_objects
|
||||
* @defgroup lwm2m_objects_device Device LwM2M object
|
||||
* @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
|
||||
@ -29,6 +56,7 @@ extern "C" {
|
||||
#include <string.h>
|
||||
|
||||
#include "liblwm2m.h"
|
||||
#include "lwm2m_client.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
|
||||
|
433
pkg/wakaama/include/objects/security.h
Normal file
433
pkg/wakaama/include/objects/security.h
Normal 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 */
|
||||
/** @} */
|
Binary file not shown.
@ -2,7 +2,6 @@ MODULE = wakaama_client
|
||||
|
||||
SRC = \
|
||||
object_server.c \
|
||||
object_security.c \
|
||||
object_access_control.c \
|
||||
#
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user