Skip to content

Commit

Permalink
lib: uicc_lwm2m: Add UICC LwM2M library
Browse files Browse the repository at this point in the history
Add functionality to read LwM2M bootstrap data from UICC.

Signed-off-by: Stig Bjørlykke <stig.bjorlykke@nordicsemi.no>
  • Loading branch information
stig-bjorlykke committed Sep 27, 2024
1 parent 9c7c28c commit 6db1f9e
Show file tree
Hide file tree
Showing 24 changed files with 1,198 additions and 0 deletions.
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

# 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
30 changes: 30 additions & 0 deletions doc/nrf/libraries/modem/uicc_lwm2m.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.. _lib_uicc_lwm2m:

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

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

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

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

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

Configuration
*************

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

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

| Header file: :file:`include/modem/uicc_lwm2m.h`
| Source file: :file:`lib/uicc_lwm2m/uicc_lwm2m.c`
.. doxygengroup:: uicc_lwm2m
:project: nrf
:members:
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 `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 read 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

0 comments on commit 6db1f9e

Please sign in to comment.