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 Aug 13, 2024
1 parent 5cb8557 commit 2b7c0ed
Show file tree
Hide file tree
Showing 20 changed files with 1,155 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ Kconfig* @tejlmand
/lib/pcm_stream_channel_modifier/ @nrfconnect/ncs-audio
/lib/sample_rate_converter/ @andvib @gWacey
/lib/tone/ @nrfconnect/ncs-audio
/lib/uicc_lwm2m/ @stig-bjorlykke
/modules/ @tejlmand
/modules/hostap/ @krish2718 @jukkar @rado17 @sachinthegreen @rlubos
/modules/mcuboot/ @de-nordic @nordicjm
Expand Down Expand Up @@ -189,6 +190,7 @@ Kconfig* @tejlmand
/samples/cellular/modem_trace_flash/ @eivindj-nordic
/samples/cellular/slm_shell/ @MarkusLassila @tomi-font
/samples/cellular/sms/ @trantanen @tokangas
/samples/cellular/uicc_lwm2m/ @stig-bjorlykke
/samples/openthread/ @rlubos @edmont @canisLupus1313 @maciejbaczmanski
/samples/nrf_profiler/ @pdunaj
/samples/peripheral/radio_test/ @KAGA164 @maje-emb
Expand Down Expand Up @@ -329,6 +331,7 @@ Kconfig* @tejlmand
/tests/lib/pcm_stream_channel_modifier/ @nrfconnect/ncs-audio
/tests/lib/sample_rate_converter/ @andvib @gWacey
/tests/lib/tone/ @nrfconnect/ncs-audio
/tests/lib/uicc_lwm2m/ @stig-bjorlykke
/tests/modules/lib/zcbor/ @oyvindronningstad
/tests/modules/mcuboot/direct_xip/ @hakonfam
/tests/modules/mcuboot/external_flash/ @hakonfam @sigvartmh
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] p_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 *p_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 @@ -49,3 +49,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 @@ -50,5 +50,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 2b7c0ed

Please sign in to comment.