Skip to content

Commit

Permalink
lib: app_jwt: add an app core jwt generator and add a sample for usage
Browse files Browse the repository at this point in the history
Ref: NRFX-6688

Signed-off-by: Aymen LAOUINI <aymen.laouini@nordicsemi.no>
  • Loading branch information
ayla-nordicsemi committed Feb 17, 2025
1 parent 2771da8 commit 4d3dfc4
Show file tree
Hide file tree
Showing 18 changed files with 1,278 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@
/doc/nrf/includes/ @nrfconnect/ncs-doc-leads
/doc/nrf/includes/boardname_tables/sample_boardnames.txt @nrfconnect/ncs-co-doc
/doc/nrf/installation/ @nrfconnect/ncs-doc-leads @nrfconnect/ncs-vestavind-doc @nrfconnect/ncs-wayland-doc
/doc/nrf/libraries/app_jwt/ @nrfconnect/ncs-modem-doc @ayla-nordicsemi
/doc/nrf/libraries/bin/ @nrfconnect/ncs-doc-leads
/doc/nrf/libraries/bin/lwm2m_carrier/ @nrfconnect/ncs-carrier-doc
/doc/nrf/libraries/bluetooth/ @nrfconnect/ncs-si-muffin-doc @nrfconnect/ncs-dragoon-doc
Expand Down Expand Up @@ -314,6 +315,7 @@
/ext/iperf3/ @nrfconnect/ncs-code-owners @jhirsi

# Include
/include/app_jwt.h @nrfconnect/ncs-modem @ayla-nordicsemi
/include/audio/ @nrfconnect/ncs-audio
/include/audio_module/ @nrfconnect/ncs-audio
/include/bluetooth/ @nrfconnect/ncs-dragoon
Expand Down Expand Up @@ -377,6 +379,7 @@

# Libraries
/lib/adp536x/ @nrfconnect/ncs-cia
/lib/app_jwt/ @nrfconnect/ncs-modem @ayla-nordicsemi
/lib/at_cmd_parser/ @nrfconnect/ncs-co-networking @nrfconnect/ncs-modem
/lib/at_cmd_custom/ @nrfconnect/ncs-modem
/lib/at_host/ @nrfconnect/ncs-co-networking @nrfconnect/ncs-modem
Expand Down Expand Up @@ -518,6 +521,7 @@
/samples/gazell/ @leewkb4567
/samples/hw_id/ @nrfconnect/ncs-cia
/samples/ipc/ipc_service/ @nrfconnect/ncs-si-muffin
/samples/jwt/ @nrfconnect/ncs-modem @ayla-nordicsemi
/samples/keys/ @nrfconnect/ncs-aegir
/samples/matter/ @nrfconnect/ncs-matter
/samples/mpsl/ @nrfconnect/ncs-dragoon
Expand Down Expand Up @@ -637,6 +641,7 @@
/samples/gazell/**/*.rst @nrfconnect/ncs-si-muffin-doc
/samples/hw_id/*.rst @nrfconnect/ncs-cia-doc
/samples/ipc/ipc_service/*.rst @nrfconnect/ncs-si-muffin-doc
/samples/jwt/*.rst @nrfconnect/ncs-modem-doc @ayla-nordicsemi
/samples/keys/**/*.rst @nrfconnect/ncs-aegir-doc
/samples/matter/**/*.rst @nrfconnect/ncs-matter-doc
/samples/mpsl/**/*.rst @nrfconnect/ncs-dragoon-doc
Expand Down
80 changes: 80 additions & 0 deletions doc/nrf/libraries/app_jwt/app_jwt.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
.. _app_jwt:

Application JWT
###################

The Application JWT library provides access to the `JSON Web Token (JWT)`_ generation feature from application core using signing and identity services from secure core.

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

To use the library to request a JWT, complete the following steps:

1. Set the following Kconfig options to enable the library:

* :kconfig:option:`CONFIG_APP_JWT`
* :kconfig:option:`CONFIG_APP_JWT_VERIFY_SIGNATURE`
* :kconfig:option:`CONFIG_APP_JWT_PRINT_EXPORTED_PUBKEY_DER`
* :kconfig:option:`CONFIG_NRF_SECURITY`
* :Kconfig:option:`CONFIG_SSF_PSA_CRYPTO_SERVICE_ENABLED`
* :Kconfig:option:`CONFIG_SSF_DEVICE_INFO_SERVICE_ENABLED`

#. Read the device UUID (:c:func:`app_jwt_get_uuid`)
#. Populate the :c:struct:`app_jwt_data` structure with your desired values.
See `Possible structure values`_ for more information.
#. Pass the structure to the function that generates JWT (:c:func:`app_jwt_generate`).

If the function executes successfully, :c:member:`app_jwt_data.jwt_buf` will contain the JSON Web Token.

.. note::
The library doesn't check the validity of the time source, it is up to the caller to make sure that the system has access to a valid one, otherwise "iat" field will containt the time since boot in seconds.

Possible structure values
=========================

You can configure the following values in the :c:struct:`app_jwt_data` structure:

* :c:member:`app_jwt_data.sec_tag` - Optional, kept for compatibility reasons.
The ``sec_tag`` must contain a valid signing key.
Will always be ignored, the library will use the IAK for signing.
* :c:member:`app_jwt_data.key` - Required if ``sec_tag`` is not zero.
Defines the type of key in the sec tag.
Will always be ignored, the library will use the IAK for signing.
* :c:member:`app_jwt_data.alg` - Required, always use the value JWT_ALG_TYPE_ES256.
Defines the JWT signing algorithm. Currently, only ECDSA 256 is supported.
* :c:member:`app_jwt_data.validity_s` - Optional.
Defines the expiration date for the JWT.
If set to 0, the field ``exp`` will be omitted from the generated JWT.
* :c:member:`app_jwt_data.subject` - Optional.
Corresponds to ``sub`` claim.
Use ``NULL`` if you want to leave out this field.
* :c:member:`app_jwt_data.audience` - Optional.
Corresponds to ``aud`` claim.
Use ``NULL`` if you want to leave out this field.
* :c:member:`app_jwt_data.jwt_buf` - Required.
Buffer for the generated, null-terminated, JWT string.
Buffer size has to be al least 600 bytes, at most 900 bytes.
The user has to provide a valid buffer, library doesn't do any allocation.
* :c:member:`app_jwt_data.jwt_sz` - Size of JWT buffer.
Required, has to be equal to the size of :c:member:`app_jwt_data.jwt_buf`.

Hardcoded values in the generated JWT
=====================================

The generated JWT will always contain the following information in the next fields:

* ``kid`` - KeyID.
SHA256 of the signing key.
* ``jti`` - Json Token ID.
will always contain <Board_ID>.<16 Random bytes formatted as UUID>.
* ``iss`` - Issuer.
will always contain <Board_ID>.<content of ``sub`` claim>.


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

| Header file: :file:`include/app_jwt.h`
| Source file: :file:`lib/app_jwt/app_jwt.c`
.. doxygengroup:: app_jwt
11 changes: 11 additions & 0 deletions doc/nrf/libraries/app_jwt/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.. _lib_app_jwt:

Library Application JWT
########################

.. toctree::
:maxdepth: 1
:glob:
:caption: Subpages:

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

#ifndef _APP_JWT_H
#define _APP_JWT_H

#ifdef __cplusplus
extern "C" {
#endif

/**
* @file app_jwt.h
*
* @brief Generate a JWT with from application core.
* @defgroup app_jwt JWT generation
* @{
*
*/

#include <stdint.h>
#include <strings.h>

/** @brief Maximum size of a JWT string, could be used to allocate JWT
* output buffer.
*/
#define APP_JWT_STR_MAX_LEN 900

/** @brief Maximum valid duration for JWTs generated by user application */
#define APP_JWT_VALID_TIME_S_MAX (7 * 24 * 60 * 60)

/** @brief Default valid duration for JWTs generated by user application */
#define APP_JWT_VALID_TIME_S_DEF (10 * 60)

/** @brief UUID size in bytes */
#define APP_JWT_UUID_BYTE_SZ 16

/** @brief UUID v4 format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx */
#define APP_JWT_UUID_V4_STR_LEN ((APP_JWT_UUID_BYTE_SZ * 2) + 4)

/** @brief The type of key to be used for signing the JWT. */
enum app_jwt_key_type {
JWT_KEY_TYPE_CLIENT_PRIV = 2,
JWT_KEY_TYPE_ENDORSEMENT = 8,
};

/** @brief JWT signing algorithm */
enum app_jwt_alg_type {
JWT_ALG_TYPE_ES256 = 0,
};

/** @brief JWT parameters required for JWT generation and pointer to generated JWT */
struct app_jwt_data {
/** Sec tag to use for JWT signing */
unsigned int sec_tag;
/** Key type in the specified sec tag */
enum app_jwt_key_type key;
/** JWT signing algorithm */
enum app_jwt_alg_type alg;

/**
* Defines how long the JWT will be valid; in seconds (from generation).
* The 'iat' and 'exp' claims will be populated either the application
* has or not a valid date and time.
*/
uint32_t validity_s;

/** NULL terminated 'sub' claim; the principal that is the subject of the JWT */
const char *subject;
/** NULL terminated 'aud' claim; intended recipient of the JWT */
const char *audience;

/**
* Buffer to which the NULL terminated JWT will be copied.
* It is the responsibility of the user to provide a valid buffer.
* The returned JWT could be as long as 900 bytes, use the
* defined size value APP_JWT_STR_MAX_LEN to create your supplied return buffer.
*/
char *jwt_buf;
/** Size of the user provided buffer. */
size_t jwt_sz;
};

/**
* @brief Generates a JWT using the supplied parameters. If successful,
* the JWT string will be stored in the supplied struct.
* The user is responsible for providing a valid pointer to store the JWT.
*
* Subject and audience fields may be NULL in which case those fields are left out
* from generated JWT token.
*
* The API doesn't verify the time source validity, it is up to the caller to make sure
* that the system has access to a valid time source, otherwise "iat" field will
* contain the time since boot in seconds.
*
* JWT is signed with the application identity attestation key, no matter what
* value is supplied in the sec_tag.
*
* @param[in,out] jwt Pointer to struct containing JWT parameters and result.
*
* @retval 0 If the operation was successful.
* Otherwise, a (negative) error code is returned, check header errno.h for a full list.
*/
int app_jwt_generate(struct app_jwt_data *const jwt);

/**
* @brief Gets the device UUID from the secure domain
* and returns it as a NULL terminated string in the supplied buffer.
* The device UUID can be used as a device identifier for cloud services and
* for secure device management using the nRF Cloud Identity Service.
*
* UUID v4 defined by ITU-T X.667 | ISO/IEC 9834-8 has a length of 35 bytes, add
* 1 byte for the atring termination character. User is expected to provide a buffer
* of at least 36 bytes.
*
* @param[out] uuid_buffer Pointer to buffer where the device UUID string will be written to.
* @param[in] uuid_buffer_size Size of the provided buffer.
*
* @retval 0 If the operation was successful.
* Otherwise, a (negative) error code is returned, check header errno.h for a full list.
*/
int app_jwt_get_uuid(char *uuid_buffer, const size_t uuid_buffer_size);

/** @} */

#ifdef __cplusplus
}
#endif

#endif /* _APP_JWT_H */
1 change: 1 addition & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ add_subdirectory_ifdef(CONFIG_HW_ID_LIBRARY hw_id)
add_subdirectory_ifdef(CONFIG_EDGE_IMPULSE edge_impulse)
add_subdirectory_ifdef(CONFIG_WAVE_GEN_LIB wave_gen)
add_subdirectory_ifdef(CONFIG_HW_UNIQUE_KEY_SRC hw_unique_key)
add_subdirectory_ifdef(CONFIG_APP_JWT app_jwt)
add_subdirectory_ifdef(CONFIG_MODEM_JWT modem_jwt)
add_subdirectory_ifdef(CONFIG_MODEM_SLM modem_slm)
add_subdirectory_ifdef(CONFIG_MODEM_ATTEST_TOKEN modem_attest_token)
Expand Down
1 change: 1 addition & 0 deletions lib/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

menu "Libraries"

rsource "app_jwt/Kconfig"
rsource "bin/Kconfig"
rsource "nrf_modem_lib/Kconfig"
rsource "adp536x/Kconfig"
Expand Down
11 changes: 11 additions & 0 deletions lib/app_jwt/CMakeLists.txt
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
#

zephyr_library()

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

menuconfig APP_JWT
bool "Application JWT Library"
depends on SSF_CLIENT && SSF_PSA_CRYPTO_SERVICE_ENABLED && SSF_DEVICE_INFO_SERVICE_ENABLED
select BASE64
# Needed for time and date
select POSIX_API
# Needed to print integer values in JSON
select CJSON_LIB
select CBPRINTF_FP_SUPPORT

if APP_JWT

config APP_JWT_VERIFY_SIGNATURE
bool "Verify signature after signing"
default y

config APP_JWT_PRINT_EXPORTED_PUBKEY_DER
bool "Print to terminal the DER formatted public key"

module=APP_JWT
module-str=User App JWT
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"

endif # APP_JWT
Loading

0 comments on commit 4d3dfc4

Please sign in to comment.