Skip to content

feat: enable oscore credentials lookup and storage#1911

Open
BitFis wants to merge 1 commit intoobgm:developfrom
BitFis:feat/enable-external-oscore-credentials
Open

feat: enable oscore credentials lookup and storage#1911
BitFis wants to merge 1 commit intoobgm:developfrom
BitFis:feat/enable-external-oscore-credentials

Conversation

@BitFis
Copy link
Copy Markdown

@BitFis BitFis commented Mar 10, 2026

Work related to #1892

Enabling:

  • ensure oscore ctx is cleaned up
  • allow storage and provide oscore credentials via find function
  • write example to load oscore credentials from file system, using -O
  • add API functions to override find and store echo and PIV / window values for storage

OPEN:

  • separate echo handler into a read and write handler
  • remove old structure, only expand via callback and config defintions

@BitFis BitFis changed the title feat: enable oscore credentials lookup and storage Draft: feat: enable oscore credentials lookup and storage Mar 10, 2026
@mrdeep1
Copy link
Copy Markdown
Collaborator

mrdeep1 commented Mar 10, 2026

It is worth installing and running pre-commit to tidy up the source formatting.

@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch 5 times, most recently from fdc8821 to 42c2033 Compare March 10, 2026 16:05
@mrdeep1
Copy link
Copy Markdown
Collaborator

mrdeep1 commented Mar 10, 2026

I suggest that you go through all the failed tasks and fix the associated issue before doing the next push. There is some overlap, but a lot of discrete issues that need to get fixed.

@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch 3 times, most recently from 3b6f3cd to bd0d278 Compare March 10, 2026 17:31
@BitFis
Copy link
Copy Markdown
Author

BitFis commented Mar 10, 2026

I suggest that you go through all the failed tasks and fix the associated issue before doing the next push. There is some overlap, but a lot of discrete issues that need to get fixed.

Apologies for the spam, I am used to that all runs are canceled automatically if a new push has triggered it.

@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch from bd0d278 to 23a3852 Compare March 10, 2026 17:54
@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch 4 times, most recently from 57a1bb3 to d2cd11c Compare March 19, 2026 20:56
@BitFis
Copy link
Copy Markdown
Author

BitFis commented Mar 19, 2026

@mrdeep1 please have another look. I will finalize it next week, but please check if this follows the appropriate format.
I followed up now the coap_oscore*_conf_t format. Which means, the find function returns the config object, which then internally is converted to the oscore ctx. This removes the need to provide access to the underlying oscore ctx, enabling for internal optimisations. But to enable that echo challange and PIV + window work as expected, I had to add some additional handlers. Also I added a lifetime tracker recipiant->ref to ensure that the oscore temporary credentials can be safely cleaned up, it seems something like it is required, since the recipient currently could be removed and may lead to unexpected behavior if still referenced.

For now maybe focus on the API expansions in coap_oscore and the general flow. I will cleanup some internals next week, so it should then be ready for final scrutiny should this approach be fine.

@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch 11 times, most recently from c70a91d to e094227 Compare March 26, 2026 22:41
@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch from 44ed81f to 636686f Compare March 30, 2026 15:17
@mrdeep1
Copy link
Copy Markdown
Collaborator

mrdeep1 commented Mar 30, 2026

Thanks. I will re-run compatibility tests which takes a bit of time and see what gets reported.

The compile error I am not able to reproduce using gcc-11 and gcc-15 (latest).

I'm using gcc-13 on ubuntu24 and -fsanitize=address,undefined. The update code builds fine this time. It looked like the check was doing a sizeof(p) to see whether it was safe to overwrite - a 64bit hex value was too much for the pointer size which was 8 bytes.

The recipient context will need to be extended to support group mode or pairwise mode and public key at a minimum, along with silent server.

@BitFis
Copy link
Copy Markdown
Author

BitFis commented Mar 31, 2026

Thanks. I will re-run compatibility tests which takes a bit of time and see what gets reported.

Brilliant, thanks for verifying

The recipient context will need to be extended to support group mode or pairwise mode and public key at a minimum, along with silent server.

With the provided implementation, the extension should be relative easy, so I don't see an issue for those extensions I would say 👍

@mrdeep1
Copy link
Copy Markdown
Collaborator

mrdeep1 commented Mar 31, 2026

The compatibility tests ran fine overnight.

I will start on reviewing the code later today / tomorrow.

Copy link
Copy Markdown
Collaborator

@mrdeep1 mrdeep1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general looking OK.

2 commits need to be merged into 1.

Comment thread include/coap3/coap_oscore.h
Comment thread include/coap3/coap_oscore.h
Comment thread include/coap3/coap_oscore_internal.h
Comment thread include/oscore/oscore_context.h
Comment thread man/coap-oscore-conf.txt.in
Comment thread src/coap_oscore.c Outdated
Comment thread src/coap_oscore.c Outdated
Comment thread src/coap_oscore.c Outdated
Comment thread src/coap_oscore.c Outdated
if (conf->sender_id.sender_id) {
coap_delete_bin_const(conf->sender_id.sender_id);
}
conf->sender_id.sender_id = new_sender_id;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlikely that multiple threads are doing this concurrently, but this is not thread safe.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are now multiple returns from coap_oscore_conf_set_snd() which leave the global lock locked.

I suggest that you rename coap_oscore_conf_set_snd() to coap_oscore_conf_set_snd_lkd() and create a wrapper like coap_oscore_conf_add_rcp() and remove coap_lock* from within coap_oscore_conf_set_snd_lkd().

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure that this function can be used at all safely within the find function callback. Are you sure a lock is required. Since for me it seems the conf pointer is created and passed into libcoap. So never shared between libcoap and the application. Maybe adding a information that the function is not thread safe, but the conf should never really be accessed by multiple threads. Thougth not sure, if you have some plans into another direction.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A part of me questions whether we need this function at all, unless we build the entire configuration without using a configuration file.

As we are just building a configuration file from a single thread, then we can get away with no locking. However, it should not be called twice and so replacing a now stale copy of sender_id is unexpected. But someone will try to do that.. If it is updated from find function, that could be executing in any thread.

I also think you have got away with sender_id still working with the configuration file with

CONFIG_ENTRY(sender_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),

and so sender_id.sender_id just happens to work when updating the top level sender_id.

Copy link
Copy Markdown
Author

@BitFis BitFis Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is correct, generally I see a benefit of being able to build the configuration without the configuration file. I believe this is an important optimization in the future, to then also potentially enable passing the memory from application space to optimize on ram usage.
For the example case in the server, it shows well, to achieve the same functionality, the file memory would need to be manipulated before passing to the coap_new_oscore_conf. which I believe is not a great way to handle it. But it is an option and maybe a first step instead of adding those functions?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used previous PR as base, added integer64 type to ensure whole sequence number and window can be covered

Comment thread src/coap_oscore.c Outdated
coap_delete_bin_const(conf->id_context);
}

conf->id_context = id_context;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlikely that multiple threads are doing this concurrently, but this is not thread safe.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coap_oscore_conf_set_context_id() has same return issue as coap_oscore_conf_set_snd(). Suggest things are fixed in the same way.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch 5 times, most recently from 3fcadcf to 8eaadb6 Compare April 6, 2026 13:55
Copy link
Copy Markdown
Author

@BitFis BitFis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resovled most comments, a few open with comments. I think you should be able to easily check that I resolved them as expected, but if not, will happily reopen and you can close them from your side.
Commits merged into one with updated commit message, feel free to comment.

Comment thread src/coap_oscore.c Outdated
for (i = 0; i < oscore_conf->recipient_id_count; i++) {
coap_delete_bin_const(oscore_conf->recipient_id[i]);
coap_delete_bin_const(oscore_conf->sender_id.sender_id);
coap_oscore_rcp_conf_t *current = oscore_conf->recipient_id;
Copy link
Copy Markdown
Author

@BitFis BitFis Apr 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had the same thought, but it will brake the file format / unclear how to manage in the parsing case:

CONFIG_ENTRY(sender_id, COAP_ENC_HEX | COAP_ENC_ASCII, NULL),`

any ideas? Feels like breaking API change.

Comment thread src/coap_oscore.c Outdated
Comment thread src/coap_oscore.c
@BitFis BitFis requested a review from mrdeep1 April 6, 2026 14:04
Copy link
Copy Markdown
Collaborator

@mrdeep1 mrdeep1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some resolved re-opened.

@BitFis BitFis requested a review from mrdeep1 April 6, 2026 15:49
@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch 2 times, most recently from 09718a2 to 9b9f445 Compare April 6, 2026 16:20
@mrdeep1
Copy link
Copy Markdown
Collaborator

mrdeep1 commented Apr 8, 2026

Please see #1952 for a backport from the libcoap OSCORE Group work to support complex sender / recipient configuration definitions.

I also note that several comments have not been resolved in the blocks of 'hidden conversations'.

@BitFis
Copy link
Copy Markdown
Author

BitFis commented Apr 12, 2026

Please see #1952 for a backport from the libcoap OSCORE Group work to support complex sender / recipient configuration definitions.

I also note that several comments have not been resolved in the blocks of 'hidden conversations'.

With this input, I guess best to build on #1952 by expanding the coap_oscore_rcp_conf_t type with SSN (Sequence Synchronization Number) handling fields. Which enables injecting these values at configuration time (maybe not required if using a different approach from later in the comment):

/* SSN handling for rfc8613 B.1.2 */
uint8_t echo_value[8];              /** Inject an echo value for oscore credentials */
uint8_t window_initialized;         /**< Sliding window initialization status (@c 1 initialized, @c 0 otherwise) */
uint64_t last_seq;                  /**< Highest sequence number used for this recipient */
uint64_t sliding_window;            /**< Bitfield sequence counter window */

Additionally I propose to drop all current config setter functions in this PR, eliminating threading concerns around config object creation discussions.

With that, the question stays, how to effectively provide echo values and window state. I see three options:

  1. Simple setter functions - Provide coap_oscore_conf_set_seq_num() and coap_oscore_conf_set_echo() targeting the first recipient entry only. (no threading to allow using those inside the find function)
  2. Register callback functions - More flexible but increases application implementation complexity.
  3. Integrate into the find function - Return echo/window via the find function either as a return struct or output arguments.

I lean toward option 1, but I'm open to alternatives. I'd like your input before proceeding further. Thanks, @mrdeep1.

@mrdeep1
Copy link
Copy Markdown
Collaborator

mrdeep1 commented Apr 13, 2026

With this input, I guess best to build on 1952 by expanding the coap_oscore_rcp_conf_t type with SSN...

Agreed. One of the reasons for doing #1952 as coap_oscore_rcp_conf_t is expanded for group support.

Additionally I propose to drop all current config setter functions in this PR,....

If you wrap any callback invocations with coap_lock_callback(() or coap_lock_callback_ret(), then it is safe for the callback to invoke a libcoap function that does a call_lock_lock(). This should remove a lot of threading concerns.

With that, the question stays, how to effectively provide echo values and window state.

I think I would persevere with 2 at this point.

@BitFis BitFis marked this pull request as draft April 25, 2026 16:44
@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch 5 times, most recently from 39daed9 to 4c7c7cb Compare April 26, 2026 16:47
@BitFis
Copy link
Copy Markdown
Author

BitFis commented Apr 26, 2026

@mrdeep1 update accordingly, dropped the API extensions besides register handlers.
However I moved loading the echo, window and last sequence counter via config in.
Felt simpler then adding multiple functions. Please check if the current approach is sufficient.

@BitFis BitFis marked this pull request as ready for review April 26, 2026 16:50
Add reference counting to recipient contexts so they can be safely removed
while still in use by active sessions. Expose callback hooks for credential
lookup, echo, and sequence storage to allow custom backends.
Expand example server to demonstrate the external storage via a simple
file based database. Expand coap_oscore_rcp_conf_t to enable settings
preconfigured echo value, sequence counter and window value as uint64
Enable temporary credentials returned by the find function and are destroyed
after use.
@BitFis BitFis force-pushed the feat/enable-external-oscore-credentials branch from 4c7c7cb to a5daf79 Compare April 26, 2026 16:53
Copy link
Copy Markdown
Collaborator

@mrdeep1 mrdeep1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this work.

I'm currently running regression tests to see if any issues raised.

Comment thread src/coap_oscore.c
rcp_ctx->last_seq = incoming_seq;
} else if (session->context->oscore_update_seq_num_cb != NULL) {
/* notify custom credential storage */
session->context->oscore_update_seq_num_cb(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coap_lock_callback(session->context->oscore_update_seq_num_cb(

Allow oscore_update_seq_num_cb() to call a libcoap function safely.

Comment thread src/coap_oscore.c
} else {
if (session->context->oscore_update_seq_num_cb != NULL) {
/* notify echo challenge changed */
session->context->oscore_update_seq_num_cb(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coap_lock_callback(session->context->oscore_update_seq_num_cb(

Allow oscore_update_seq_num_cb() to call a libcoap function safely.

Comment thread src/coap_oscore.c

/* reset echo challenge value to prevent duplicate reuse */
if (session->context->oscore_update_echo_cb != NULL) {
session->context->oscore_update_echo_cb(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coap_lock_callback(session->context->oscore_update_echo_cb(

Allow oscore_update_echo_cb() to call a libcoap function safely.

Comment thread src/coap_oscore.c
coap_prng_lkd(rcp_ctx->echo_value, sizeof(rcp_ctx->echo_value));
}
if (session->context->oscore_update_echo_cb != NULL) {
session->context->oscore_update_echo_cb(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

coap_lock_callback(session->context->oscore_update_echo_cb(

Allow oscore_update_echo_cb() to call a libcoap function safely.

Comment thread tests/test_oscore.c
const coap_str_const_t conf = { sizeof(conf_data) - 1,
(const uint8_t *)conf_data
};
coap_oscore_conf_t *oscore_conf = NULL;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add in (to stop WARN errors)

  coap_set_log_level(COAP_LOG_CRIT);

Comment thread tests/test_oscore.c
(const uint8_t *)conf_data
};
coap_oscore_conf_t *oscore_conf;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add in (to stop WARN errors)

  coap_set_log_level(COAP_LOG_CRIT);

Comment thread tests/test_oscore.c
(const uint8_t *)conf_data
};
coap_oscore_conf_t *oscore_conf;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add in (to stop WARN errors)

  coap_set_log_level(COAP_LOG_CRIT);

Comment thread tests/test_oscore.c
(const uint8_t *)conf_data
};
coap_oscore_conf_t *oscore_conf;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add in (to stop WARN errors)

  coap_set_log_level(COAP_LOG_CRIT);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants