From 79426d618d70fb756014bb0a0ebb07f1e00f7ea1 Mon Sep 17 00:00:00 2001 From: Patryk Jarosz Date: Wed, 6 Mar 2024 09:48:37 +0000 Subject: [PATCH] OSCORE: Added user-defined callback for finding oscore context --- include/coap3/coap_net_internal.h | 2 ++ include/coap3/coap_oscore.h | 46 ++++++++++++++++++++++++++++++- include/coap3/coap_session.h | 11 ++++++++ include/oscore/oscore_context.h | 17 ++++++++++++ man/coap_oscore.txt.in | 17 +++++++++++- man/coap_session.txt.in | 7 +++++ src/coap_net.c | 4 ++- src/coap_oscore.c | 21 +++++++++++++- src/coap_session.c | 8 ++++++ src/oscore/oscore_context.c | 26 +++++++++++++++++ 10 files changed, 155 insertions(+), 4 deletions(-) diff --git a/include/coap3/coap_net_internal.h b/include/coap3/coap_net_internal.h index 6a2e8bff32..c5469362c5 100644 --- a/include/coap3/coap_net_internal.h +++ b/include/coap3/coap_net_internal.h @@ -93,6 +93,8 @@ struct coap_context_t { #endif /* WITH_LWIP */ #if COAP_OSCORE_SUPPORT struct oscore_ctx_t *p_osc_ctx; /**< primary oscore context */ + external_oscore_find_context_handler_t external_oscore_find_context_handler; + /**< Called when oscore_find_context didn't find any context*/ #endif /* COAP_OSCORE_SUPPORT */ #if COAP_CLIENT_SUPPORT diff --git a/include/coap3/coap_oscore.h b/include/coap3/coap_oscore.h index 925b4e0fa9..e18496a275 100644 --- a/include/coap3/coap_oscore.h +++ b/include/coap3/coap_oscore.h @@ -129,12 +129,17 @@ int coap_context_oscore_server(coap_context_t *context, * * @param sender_seq_num The Sender Sequence Number to save in non-volatile * memory. + * @param recipient_id Recipient ID that could be used to find the corresponding SSN entry. + * @param id_context ID Context that could be used to find the corresponding SSN entry. * @param param The save_seq_num_func_param provided to * coap_new_oscore_context(). * * @return @c 1 if success, else @c 0 if a failure of some sort. */ -typedef int (*coap_oscore_save_seq_num_t)(uint64_t sender_seq_num, void *param); +typedef int (*coap_oscore_save_seq_num_t)(uint64_t sender_seq_num, + const coap_bin_const_t *recipient_id, + const coap_bin_const_t *id_context, + void *param); /** * Parse an OSCORE configuration (held in memory) and populate a OSCORE @@ -193,6 +198,45 @@ int coap_new_oscore_recipient(coap_context_t *context, int coap_delete_oscore_recipient(coap_context_t *context, coap_bin_const_t *recipient_id); +/** + * Opaque pointer for internal oscore_ctx_t type. + */ +typedef struct oscore_ctx_t * oscore_ctx_handle_t; + +/** + * Opaque pointer for internal oscore_recipient_ctx_t type. + * + */ +typedef struct oscore_recipient_ctx_t * oscore_recipient_ctx_handle_t; + +/** + * Optional user callback to be used, when oscore_find_context can't find any context. + * Could be used to check external storage (e.g. FLASH). + * + * @param c_context The CoAP Context to search. + * @param rcpkey_id The Recipient kid. + * @param ctxkey_id The ID Context to match (or NULL if no check). + * @param oscore_r2 Partial id_context to match against or NULL. + * @param recipient_ctx The recipient context to update. + * + * return The OSCORE context and @p recipient_ctx updated, or NULL is error. + */ +typedef oscore_ctx_handle_t (*external_oscore_find_context_handler_t)( + const coap_context_t *c_context, + const coap_bin_const_t rcpkey_id, + const coap_bin_const_t *ctxkey_id, + uint8_t *oscore_r2, + oscore_recipient_ctx_handle_t *recipient_ctx); + +/** + * Register optional user callback to be used, when oscore_find_context can't find any context. + * Callback could be used to check external storage (e.g. FLASH). + * + * @param context The current coap context to use. + * @param handler User callback. + */ +void coap_register_oscore_context_handler(coap_context_t *context, external_oscore_find_context_handler_t handler); + /** @} */ #endif /* COAP_OSCORE_H */ diff --git a/include/coap3/coap_session.h b/include/coap3/coap_session.h index 0d9ccc166c..fe8da381e1 100644 --- a/include/coap3/coap_session.h +++ b/include/coap3/coap_session.h @@ -24,6 +24,8 @@ * @{ */ +#include + /** * Abstraction of a fixed point number that can be used where necessary instead * of a float. 1,000 fractional bits equals one integer @@ -163,6 +165,15 @@ coap_proto_t coap_session_get_proto(const coap_session_t *session); */ coap_session_type_t coap_session_get_type(const coap_session_t *session); +/** + * Check if CoAP session is encrypted. + * + * @param session The CoAP session. + * + * @return True if session is encrypted, false if session is not encrypted. + */ +bool coap_session_is_encrypted(const coap_session_t *session); + /** * Get the session state * diff --git a/include/oscore/oscore_context.h b/include/oscore/oscore_context.h index 1806cccb5f..ad2803e277 100644 --- a/include/oscore/oscore_context.h +++ b/include/oscore/oscore_context.h @@ -246,6 +246,23 @@ oscore_ctx_t *oscore_find_context(const coap_context_t *c_context, uint8_t *oscore_r2, oscore_recipient_ctx_t **recipient_ctx); +/** + * oscore_find_context_in_ram - Locate recipient context (and hence OSCORE context) in RAM only + * + * @param c_context The CoAP Context to search. + * @param rcpkey_id The Recipient kid. + * @param ctxkey_id The ID Context to match (or NULL if no check). + * @param oscore_r2 Partial id_context to match against or NULL. + * @param recipient_ctx The recipient context to update. + * + * return The OSCORE context and @p recipient_ctx updated, or NULL is error. + */ +oscore_ctx_t *oscore_find_context_in_ram(const coap_context_t *c_context, + const coap_bin_const_t rcpkey_id, + const coap_bin_const_t *ctxkey_id, + uint8_t *oscore_r2, + oscore_recipient_ctx_t **recipient_ctx); + void oscore_free_association(oscore_association_t *association); int oscore_new_association(coap_session_t *session, diff --git a/man/coap_oscore.txt.in b/man/coap_oscore.txt.in index 835c428ef8..6662dfcbb3 100644 --- a/man/coap_oscore.txt.in +++ b/man/coap_oscore.txt.in @@ -19,7 +19,8 @@ coap_delete_oscore_recipient, coap_new_client_session_oscore, coap_new_client_session_oscore_pki, coap_new_client_session_oscore_psk, -coap_context_oscore_server +coap_context_oscore_server, +coap_register_oscore_context_handler - Work with CoAP OSCORE SYNOPSIS @@ -57,6 +58,9 @@ coap_oscore_conf_t *_oscore_conf_);* *int coap_context_oscore_server(coap_context_t *_context_, coap_oscore_conf_t *_oscore_conf_);* +*void coap_register_oscore_context_handler(coap_context_t *context, +external_oscore_find_context_handler_t handler);* + For specific (D)TLS library support, link with *-lcoap-@LIBCOAP_API_VERSION@-notls*, *-lcoap-@LIBCOAP_API_VERSION@-gnutls*, *-lcoap-@LIBCOAP_API_VERSION@-openssl*, *-lcoap-@LIBCOAP_API_VERSION@-mbedtls* @@ -191,6 +195,17 @@ The *coap_context_oscore_server*() function is used to enable the server to support OSCORE incoming sessions. It updates _context_ with the OSCORE configure _oscore_conf_ (which is freed off by this call). +*Function: coap_register_oscore_context_handler()* + +The *coap_register_oscore_context_handler*() function is used to register +an optional, external callback, which will be called if no OSCORE context +is found by oscore_find_context. It can be used by the user to provide an +external source of OSCORE contexts, e.g. a non-volatile memory. +Together with user-defined coap_oscore_save_seq_num_t callback provided +while creating the context, this mechanism may be used to periodically +store Sender Sequence Number field - thus providing a way to fully restore +the context after the device reboots. + RETURN VALUES ------------- *coap_new_client_session_oscore*(), *coap_new_client_session_oscore_psk*() diff --git a/man/coap_session.txt.in b/man/coap_session.txt.in index 977f206fe2..c705b54766 100644 --- a/man/coap_session.txt.in +++ b/man/coap_session.txt.in @@ -26,6 +26,7 @@ coap_session_get_proto, coap_session_get_state, coap_session_get_tls, coap_session_get_type, +coap_session_is_encrypted, coap_session_get_psk_hint, coap_session_get_psk_key - Work with CoAP sessions @@ -68,6 +69,8 @@ coap_tls_library_t *tls_lib);* *coap_session_type_t coap_session_get_type(const coap_session_t *_session_);* +*bool coap_session_is_encrypted(const coap_session_t *session);* + *const coap_bin_const_t *coap_session_get_psk_hint( const coap_session_t *_session_);* @@ -216,6 +219,8 @@ COAP_SESSION_TYPE_HELLO /* Negotiating a (D)TLS session */ The *coap_session_get_type*() function is used to get the session type from the _session_. +The *coap_session_is_encrypted*() function is used to check if incoming _session_ is encrypted. + The *coap_session_get_psk_hint*() function is used to get the current server _session_'s pre-shared-key identity hint. @@ -253,6 +258,8 @@ error. *coap_session_get_type*() returns the current session's type or 0 on error. +*coap_session_is_encrypted*() returns true if the session is using OSCORE encryption, or false if plain CoAP packets are used. + *coap_session_get_psk_hint*() returns the current server session's pre-shared-key identity hint, or NULL if not defined. diff --git a/src/coap_net.c b/src/coap_net.c index 625fd4e5d0..83aa0892a2 100644 --- a/src/coap_net.c +++ b/src/coap_net.c @@ -717,7 +717,9 @@ coap_option_check_critical(coap_session_t *session, case COAP_OPTION_OSCORE: /* Valid critical if doing OSCORE */ #if COAP_OSCORE_SUPPORT - if (ctx->p_osc_ctx) + /* Only accept OSCORE option if any OSCORE context is available, + or the user provided an external handler for finding the context. */ + if ((ctx->p_osc_ctx) || (ctx->external_oscore_find_context_handler)) break; #endif /* COAP_OSCORE_SUPPORT */ /* Fall Through */ diff --git a/src/coap_oscore.c b/src/coap_oscore.c index e0fb229474..afc51349f1 100644 --- a/src/coap_oscore.c +++ b/src/coap_oscore.c @@ -403,6 +403,8 @@ coap_oscore_new_pdu_encrypted(coap_session_t *session, /* Only update at ssn_freq rate */ osc_ctx->sender_context->next_seq += osc_ctx->ssn_freq; osc_ctx->save_seq_num_func(osc_ctx->sender_context->next_seq, + rcp_ctx->recipient_id, + osc_ctx->id_context, osc_ctx->save_seq_num_func_param); } } @@ -808,7 +810,10 @@ coap_oscore_decrypt_pdu(coap_session_t *session, if (opt == NULL) return NULL; - if (session->context->p_osc_ctx == NULL) { + /* OSCORE should be processed only if any OSCORE context is available, + or the user provided an external handler for finding the context. */ + if ((session->context->p_osc_ctx == NULL) && + (session->context->external_oscore_find_context_handler == NULL)) { coap_log_warn("OSCORE: Not enabled\n"); if (!coap_request) coap_handle_event(session->context, @@ -2106,6 +2111,13 @@ coap_delete_oscore_recipient(coap_context_t *context, return oscore_delete_recipient(context->p_osc_ctx, recipient_id); } +void +coap_register_oscore_context_handler(coap_context_t *context, external_oscore_find_context_handler_t handler) +{ + assert(context); + context->external_oscore_find_context_handler = handler; +} + /** @} */ #else /* !COAP_OSCORE_SUPPORT */ @@ -2202,4 +2214,11 @@ coap_delete_oscore_recipient(coap_context_t *context, return 0; } +void +coap_register_oscore_context_handler(coap_context_t *context, external_oscore_find_context_handler_t handler) +{ + (void)context; + (void)handler; +} + #endif /* !COAP_OSCORE_SUPPORT */ diff --git a/src/coap_session.c b/src/coap_session.c index 0a6e743fdc..c29634a421 100644 --- a/src/coap_session.c +++ b/src/coap_session.c @@ -1666,6 +1666,14 @@ coap_session_get_type(const coap_session_t *session) { return 0; } +bool +coap_session_is_encrypted(const coap_session_t *session) { + #if COAP_OSCORE_SUPPORT + return (session->oscore_encryption != 0); + #endif + return false; +} + #if COAP_CLIENT_SUPPORT int coap_session_set_type_client(coap_session_t *session) { diff --git a/src/oscore/oscore_context.c b/src/oscore/oscore_context.c index f9cd856235..c9a1338dc5 100644 --- a/src/oscore/oscore_context.c +++ b/src/oscore/oscore_context.c @@ -187,6 +187,32 @@ oscore_find_context(const coap_context_t *c_context, const coap_bin_const_t *ctxkey_id, uint8_t *oscore_r2, oscore_recipient_ctx_t **recipient_ctx) { + oscore_ctx_t *osc_ctx = oscore_find_context_in_ram(c_context, rcpkey_id, ctxkey_id, oscore_r2, recipient_ctx); + if( NULL != osc_ctx ) + { + return osc_ctx; + } + + /* no context was found in libcoap RAM - call user function to also check external storage (e.g. FLASH) */ + if (c_context->external_oscore_find_context_handler) + { + return c_context->external_oscore_find_context_handler(c_context, rcpkey_id, ctxkey_id, oscore_r2, recipient_ctx); + } + return NULL; +} + +/* + * oscore_find_context_in_ram + * Finds OSCORE context in RAM for rcpkey_id and optional ctxkey_id + * rcpkey_id can be 0 length. + * Updates recipient_ctx. + */ +oscore_ctx_t * +oscore_find_context_in_ram(const coap_context_t *c_context, + const coap_bin_const_t rcpkey_id, + const coap_bin_const_t *ctxkey_id, + uint8_t *oscore_r2, + oscore_recipient_ctx_t **recipient_ctx) { oscore_ctx_t *pt = c_context->p_osc_ctx; *recipient_ctx = NULL;