Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lib: uicc_lwm2m: Add UICC LwM2M library #16855

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .checkpatch.conf
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@
--exclude applications/nrf5340_audio/src/utils/macros
--exclude lib/at_parser/generated
--exclude lib/bin/lwm2m_carrier/include
--exclude tests/lib/uicc_lwm2m
3 changes: 3 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
/lib/pcm_stream_channel_modifier/ @nrfconnect/ncs-audio
/lib/sample_rate_converter/ @nrfconnect/ncs-audio
/lib/tone/ @nrfconnect/ncs-audio
/lib/uicc_lwm2m/ @stig-bjorlykke
stig-bjorlykke marked this conversation as resolved.
Show resolved Hide resolved

# Modules
/modules/ @nrfconnect/ncs-co-build-system
Expand Down Expand Up @@ -203,6 +204,7 @@
/samples/cellular/modem_trace_flash/ @eivindj-nordic
/samples/cellular/slm_shell/ @nrfconnect/ncs-iot-oulu
/samples/cellular/sms/ @trantanen @tokangas
/samples/cellular/uicc_lwm2m/ @stig-bjorlykke
/samples/openthread/ @nrfconnect/ncs-co-networking @nrfconnect/ncs-thread
/samples/nrf_profiler/ @nrfconnect/ncs-si-bluebagel
/samples/nrf_rpc/protocols_serialization/ @nrfconnect/ncs-protocols-serialization
Expand Down Expand Up @@ -383,6 +385,7 @@
/tests/lib/pcm_stream_channel_modifier/ @nrfconnect/ncs-audio
/tests/lib/sample_rate_converter/ @nrfconnect/ncs-audio
/tests/lib/tone/ @nrfconnect/ncs-audio
/tests/lib/uicc_lwm2m/ @stig-bjorlykke
/tests/mocks/nrf_rpc/ @nrfconnect/ncs-protocols-serialization
/tests/modules/lib/zcbor/ @oyvindronningstad
/tests/modules/mcuboot/direct_xip/ @nrfconnect/ncs-pluto
Expand Down
28 changes: 28 additions & 0 deletions doc/nrf/libraries/modem/uicc_lwm2m.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.. _lib_uicc_lwm2m:

UICC LwM2M
##########

.. contents::
:local:
:depth: 2

The UICC LwM2M library provides functionality to read LwM2M bootstrap configuration from SIM.

Configuration
stig-bjorlykke marked this conversation as resolved.
Show resolved Hide resolved
*************

To enable the UICC LwM2M library, configure the :kconfig:option:`CONFIG_UICC_LWM2M` Kconfig option.

Dependencies
************

The UICC LwM2M library requires the :ref:`nrfxlib:nrf_modem` library to use AT commands.

API documentation
*****************

| Header file: :file:`include/modem/uicc_lwm2m.h`
| Source file: :file:`lib/uicc_lwm2m/uicc_lwm2m.c`

.. doxygengroup:: uicc_lwm2m
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,10 @@ Cellular samples

* Added a call to the :c:func:`nrf_cloud_print_details` function and removed redundant logging.

* :ref:`uicc_lwm2m_sample` sample:

* Added the :ref:`uicc_lwm2m_sample` sample.

Cryptography samples
--------------------

Expand Down Expand Up @@ -687,6 +691,8 @@ Modem libraries
The :ref:`at_parser_readme` is a library that parses AT command responses, notifications, and events.
Compared to the deprecated :ref:`at_cmd_parser_readme` library, it does not allocate memory dynamically and has a smaller footprint.
For more information on how to transition from the :ref:`at_cmd_parser_readme` library to the :ref:`at_parser_readme` library, see the :ref:`migration guide <migration_2.8_recommended>`.
* The :ref:`lib_uicc_lwm2m` library.
The :ref:`lib_uicc_lwm2m` is a library that reads LwM2M bootstrap configuration from SIM.

* :ref:`at_cmd_parser_readme` library:

Expand Down
51 changes: 51 additions & 0 deletions include/modem/uicc_lwm2m.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#ifndef UICC_LWM2M_H_
#define UICC_LWM2M_H_

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* @file uicc_lwm2m.h
*
* @defgroup uicc_lwm2m UICC LwM2M
*
* @{
*
* @brief Public APIs of the UICC LwM2M library.
*/

/** UICC record max size is 256 bytes. The buffer size needed for the AT response is
* (256 * 2) + 4 bytes for SW + 1 byte for NUL. Using 516 bytes is adequate to read
* a full UICC record.
*/
#define UICC_RECORD_BUFFER_MAX ((256 * 2) + 4 + 1)

/**
* @brief Read UICC LwM2M bootstrap record.
*
* @param[inout] buffer Buffer to store UICC LwM2M bootstrap record. This buffer is also
* used internally by the function reading the AT response, so it must
* be twice the size of expected LwM2M content + 4 bytes for UICC SW.
* @param[in] buffer_size Total size of buffer.
*
* @return Length of UICC LwM2M bootstrap record, -errno on error.
*/
int uicc_lwm2m_bootstrap_read(uint8_t *buffer, int buffer_size);

/** @} */

#ifdef __cplusplus
}
#endif

#endif /* UICC_LWM2M_H_ */
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ add_subdirectory_ifdef(CONFIG_DATA_FIFO data_fifo)
add_subdirectory_ifdef(CONFIG_FEM_AL_LIB fem_al)
add_subdirectory_ifdef(CONFIG_SAMPLE_RATE_CONVERTER sample_rate_converter)
add_subdirectory_ifdef(CONFIG_NCS_BOOT_BANNER boot_banner)
add_subdirectory_ifdef(CONFIG_UICC_LWM2M uicc_lwm2m)
1 change: 1 addition & 0 deletions lib/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@ rsource "data_fifo/Kconfig"
rsource "fem_al/Kconfig"
rsource "sample_rate_converter/Kconfig"
rsource "boot_banner/Kconfig"
rsource "uicc_lwm2m/Kconfig"

endmenu
17 changes: 17 additions & 0 deletions lib/uicc_lwm2m/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

zephyr_library()

zephyr_include_directories(
${ZEPHYR_NRFXLIB_MODULE_DIR}/nrf_modem/include/
)

zephyr_library_sources(
asn1_decode.c
pkcs15_decode.c
uicc_lwm2m.c
)
11 changes: 11 additions & 0 deletions lib/uicc_lwm2m/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#
# Copyright (c) 2024 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#

config UICC_LWM2M
bool "UICC LwM2M bootstrap support"
depends on NRF_MODEM_LIB
help
"Enable UICC LwM2M bootstrap library"
83 changes: 83 additions & 0 deletions lib/uicc_lwm2m/asn1_decode.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

#include <zephyr/sys/util.h>

#include "asn1_decode.h"

bool asn1_dec_head(asn1_ctx_t *ctx, uint8_t *tag, size_t *len)
{
uint32_t hlen = 2; /* Minimum two bytes for header */

if (ctx->error || ((ctx->offset + hlen) > ctx->length)) {
/* Error detected or out of data (happens at end of sequence) */
return false;
}

*tag = ctx->asnbuf[ctx->offset++];
*len = ctx->asnbuf[ctx->offset++];

if ((*tag & 0x1F) == 0x1F) {
/* Extended tag number is unsupported */
ctx->error = true;
return false;
}

if (*len & 0x80) {
int n = *len & 0x7F;

hlen += n;
if (n > 3 || (ctx->offset + hlen) > ctx->length) {
/* Unsupported header length or out of data (header is past buffer) */
ctx->error = true;
return false;
}

*len = 0;
for (int i = 0; i < n; i++) {
*len = (*len << 8) + ctx->asnbuf[ctx->offset++];
}
}

if ((ctx->offset + *len) > ctx->length) {
/* Out of data (value is past buffer) */
ctx->error = true;
return false;
}

return true;
}

void asn1_dec_octet_string(asn1_ctx_t *ctx, size_t len, uint8_t *value, size_t max_len)
{
if (bin2hex(&ctx->asnbuf[ctx->offset], len, value, max_len) == 0) {
/* OCTET STRING too long for buffer */
ctx->error = true;
return;
}

ctx->offset += len;
}

void asn1_dec_sequence(asn1_ctx_t *ctx, size_t len, void *data, asn1_sequence_func_t sequence_func)
{
/* Create a subset from the buffer */
asn1_ctx_t seq_ctx = {
.asnbuf = &ctx->asnbuf[ctx->offset],
.length = len
};

sequence_func(&seq_ctx, data);
ctx->offset += len;

/* Copy error from subset */
ctx->error = seq_ctx.error;
}

void asn1_dec_skip(asn1_ctx_t *ctx, size_t len)
{
ctx->offset += len;
}
89 changes: 89 additions & 0 deletions lib/uicc_lwm2m/asn1_decode.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright (c) 2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/

/* A minimalistic ASN.1 BER/DER decoder (X.690).
*
* Supported types:
* OCTET STRING
* SEQUENCE / SEQUENCE OF
*/

#ifndef ASN1_DECODE_H_
#define ASN1_DECODE_H_

#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/** Commonly used ASN.1 tags. */
#define UP4 0x04
#define UP6 0x06
#define UC16 0x30
#define AP15 0x4F
#define AP16 0x50
#define CC1 0xA1
#define CC7 0xA7

/** ASN.1 context values */
typedef struct {
const uint8_t *asnbuf; /**< ASN.1 BER/DER encoded buffer */
size_t length; /**< Length of the data buffer */
uint32_t offset; /**< Current offset into asnbuf */
bool error; /**< Error detected in ASN.1 syntax */
} asn1_ctx_t;

/** Function called to handle elements in a SEQUENCE */
typedef void (*asn1_sequence_func_t)(asn1_ctx_t *ctx, void *data);

/**
* @brief Decode ASN.1 header.
*
* @param[in] ctx ASN.1 context values.
* @param[out] tag ASN.1 TAG.
* @param[out] len Length of ASN.1 value.
*
* @return true when valid ASN.1 and a value exists
*/
bool asn1_dec_head(asn1_ctx_t *ctx, uint8_t *tag, size_t *len);

/**
* @brief Decode ASN.1 OCTET STRING.
*
* @param[in] ctx ASN.1 context values.
* @param[in] len Length of octet string to decode.
* @param[out] value Decoded octet string.
* @param[in] max_len Maximum length of octet string to decode.
*/
void asn1_dec_octet_string(asn1_ctx_t *ctx, size_t len, uint8_t *value, size_t max_len);

/**
* @brief Decode ASN.1 SEQUENCE.
*
* @param[in] ctx ASN.1 context values.
* @param[in] len Length of sequence to decode.
* @param[inout] data Pointer to application specific values.
* @param[in] sequence_func Function to be called to handle sequence elements.
*/
void asn1_dec_sequence(asn1_ctx_t *ctx, size_t len, void *data, asn1_sequence_func_t sequence_func);

/**
* @brief Skip a subset of ASN.1 content.
* This is used to skip parts of the content which is not of interest.
*
* @param[in] ctx ASN.1 context values.
* @param[in] len Length of data to skip.
*/
void asn1_dec_skip(asn1_ctx_t *ctx, size_t len);

#ifdef __cplusplus
}
#endif

#endif /* ASN1_DECODE_H_ */
Loading
Loading