Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nanocoap/cache: Extend with option-only cache keygen #20043

Merged
merged 2 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions sys/include/net/nanocoap/cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,26 @@
*/
void nanocoap_cache_key_generate(const coap_pkt_t *req, uint8_t *cache_key);

/**
* @brief Generates a cache key based on only the options in @p req
*
* @param[in] req The request to generate the cache key from
* @param[out] cache_key The generated cache key of SHA256_DIGEST_LENGTH bytes
*/
void nanocoap_cache_key_options_generate(const coap_pkt_t *req, void *cache_key);

/**
* @brief Generates a cache key based on only the options in @p req without
* any of the blockwise options included in the key
*
* This function can be used to correlate individual requests that are part of a
* blockwise transfer with each other.
*
* @param[in] req The request to generate the cache key from
* @param[out] cache_key The generated cache key of SHA256_DIGEST_LENGTH bytes
*/
void nanocoap_cache_key_blockreq_options_generate(const coap_pkt_t *req, void *cache_key);

/**
* @brief Compares two cache keys.
*
Expand All @@ -242,7 +262,7 @@
*/
static inline bool nanocoap_cache_entry_is_stale(const nanocoap_cache_entry_t *ce, uint32_t now)
{
/* see https://en.wikipedia.org/w/index.php?title=Serial_number_arithmetic&oldid=1085516466#General_solution */

Check warning on line 265 in sys/include/net/nanocoap/cache.h

View workflow job for this annotation

GitHub Actions / static-tests

line is longer than 100 characters
return ((int)(now - ce->max_age) > 0);
}

Expand Down
44 changes: 38 additions & 6 deletions sys/net/application_layer/nanocoap/cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,10 @@ size_t nanocoap_cache_free_count(void)
return clist_count(&_empty_list_head);
}

void nanocoap_cache_key_generate(const coap_pkt_t *req, uint8_t *cache_key)
static void _cache_key_digest_opts(const coap_pkt_t *req, sha256_context_t *ctx,
bool include_etag,
bool include_blockwise)
{
sha256_context_t ctx;
sha256_init(&ctx);

coap_optpos_t opt = {0, 0};
uint8_t *value;

Expand All @@ -96,17 +95,50 @@ void nanocoap_cache_key_generate(const coap_pkt_t *req, uint8_t *cache_key)
if (optlen >= 0) {
/* gCoAP forward proxy is ETag-aware, so skip ETag option,
* see https://datatracker.ietf.org/doc/html/rfc7252#section-5.4.2 */
if (IS_USED(MODULE_GCOAP_FORWARD_PROXY) && (opt.opt_num == COAP_OPT_ETAG)) {
if ((!include_etag) && (opt.opt_num == COAP_OPT_ETAG)) {
continue;
}
/* skip NoCacheKey,
see https://tools.ietf.org/html/rfc7252#section-5.4.6 */
if ((opt.opt_num & 0x1E) == 0x1C) {
continue;
}
sha256_update(&ctx, value, optlen);
/* Don't include blockwise (on request) so matching between
* blockwise parts is possible */
if ((!include_blockwise) && (
(opt.opt_num == COAP_OPT_BLOCK2) ||
(opt.opt_num == COAP_OPT_BLOCK1)
)) {
continue;
}
sha256_update(ctx, &opt.opt_num, sizeof(opt.opt_num));
sha256_update(ctx, value, optlen);
}
}
}

void nanocoap_cache_key_options_generate(const coap_pkt_t *req, void *cache_key)
{
sha256_context_t ctx;
sha256_init(&ctx);
_cache_key_digest_opts(req, &ctx, true, true);
sha256_final(&ctx, cache_key);
}

void nanocoap_cache_key_blockreq_options_generate(const coap_pkt_t *req, void *cache_key)
{
sha256_context_t ctx;
sha256_init(&ctx);
_cache_key_digest_opts(req, &ctx, true, false);
sha256_final(&ctx, cache_key);
}

void nanocoap_cache_key_generate(const coap_pkt_t *req, uint8_t *cache_key)
{
sha256_context_t ctx;
sha256_init(&ctx);

_cache_key_digest_opts(req, &ctx, !(IS_USED(MODULE_GCOAP_FORWARD_PROXY)), true);
switch (req->hdr->code) {
case COAP_METHOD_FETCH:
sha256_update(&ctx, req->payload, req->payload_len);
Expand Down
55 changes: 55 additions & 0 deletions tests/unittests/tests-nanocoap_cache/tests-nanocoap_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,60 @@
/* compare 3. and 1. packet */
TEST_ASSERT(nanocoap_cache_key_compare(digest2, digest1) > 0);
}

static void test_nanocoap_cache__cachekey_blockwise(void)
{
uint8_t digest1[SHA256_DIGEST_LENGTH];
uint8_t digest2[SHA256_DIGEST_LENGTH];
uint8_t buf1[_BUF_SIZE];
uint8_t buf2[_BUF_SIZE];
coap_pkt_t pkt1;
coap_pkt_t pkt2;
uint16_t msgid = 0xABCD;
uint8_t token[2] = {0xDA, 0xEC};
char path[] = "/time";
size_t len;
coap_block1_t blockopt = {
.offset = 0,
.blknum = 0,
.szx = 2,
.more = 1,
};

/* 1. packet */
len = coap_build_hdr((coap_hdr_t *)&buf1[0], COAP_TYPE_NON,
&token[0], 2, COAP_METHOD_GET, msgid);
coap_pkt_init(&pkt1, &buf1[0], sizeof(buf1), len);
coap_opt_add_string(&pkt1, COAP_OPT_URI_PATH, &path[0], '/');
coap_opt_add_block1_control(&pkt1, &blockopt);
coap_opt_finish(&pkt1, COAP_OPT_FINISH_NONE);


Check warning on line 105 in tests/unittests/tests-nanocoap_cache/tests-nanocoap_cache.c

View workflow job for this annotation

GitHub Actions / static-tests

too many consecutive empty lines
blockopt.offset = 128;
blockopt.blknum = 2;

/* 2. packet */
len = coap_build_hdr((coap_hdr_t *)&buf2[0], COAP_TYPE_NON,
&token[0], 2, COAP_METHOD_GET, msgid);
coap_pkt_init(&pkt2, &buf2[0], sizeof(buf2), len);
coap_opt_add_string(&pkt2, COAP_OPT_URI_PATH, &path[0], '/');
coap_opt_add_block1_control(&pkt1, &blockopt);
coap_opt_finish(&pkt2, COAP_OPT_FINISH_NONE);

nanocoap_cache_key_blockreq_options_generate((const coap_pkt_t *) &pkt1, digest1);
nanocoap_cache_key_blockreq_options_generate((const coap_pkt_t *) &pkt2, digest2);

/* compare 1. and 2. packet. Should be equal except for blockwise */
TEST_ASSERT_EQUAL_INT(0, nanocoap_cache_key_compare(digest1, digest2));

/* Now with the blockwise option in the digest */
nanocoap_cache_key_options_generate((const coap_pkt_t *) &pkt1, digest1);
nanocoap_cache_key_options_generate((const coap_pkt_t *) &pkt2, digest2);

/* compare 1. and 2. packet. Should no longer be equal */
TEST_ASSERT(nanocoap_cache_key_compare(digest2, digest1) != 0);
}

static void test_nanocoap_cache__add(void)
{
uint8_t buf[_BUF_SIZE];
Expand Down Expand Up @@ -263,6 +317,7 @@
new_TestFixture(test_nanocoap_cache__add),
new_TestFixture(test_nanocoap_cache__del),
new_TestFixture(test_nanocoap_cache__cachekey),
new_TestFixture(test_nanocoap_cache__cachekey_blockwise),
new_TestFixture(test_nanocoap_cache__max_age),
};

Expand Down
Loading