jwks: Implement jwks_error_any(), jwks_item_free_bad(), and jwks_item_count()

Closes #209

Signed-off-by: Ben Collins <bcollins@libjwt.io>
This commit is contained in:
Ben Collins 2025-02-12 17:09:21 -05:00
parent b494699781
commit 0d15d75fb3
No known key found for this signature in database
GPG key ID: 5D5A57C7242B22CF
3 changed files with 103 additions and 18 deletions

View file

@ -1296,10 +1296,10 @@ int jwks_error(const jwk_set_t *jwk_set);
* the jwk_item_t in the set.
*
* @param jwk_set An existing jwk_set_t
* @return 0 if no error exists, 1 if any exists.
* @return 0 if no error exists, or the number of errors in the set
*/
JWT_EXPORT
int jwks_error_any(jwk_set_t *jwk_set);
int jwks_error_any(const jwk_set_t *jwk_set);
/**
* @brief Retrieve an error message from a jwk_set
@ -1504,9 +1504,9 @@ JWT_EXPORT
int jwks_item_key_bits(const jwk_item_t *item);
/**
* Free all memory associated with the nth jwk_item_t in a jwk_set
* @brief Free remove and free the nth jwk_item_t in a jwk_set
*
* @param jwk_set A JWKS object
* @param jwk_set Pointer to a JWKS object
* @param index the position of the item in the index
* @return 0 if no item was was deleted (found), 1 if it was
*/
@ -1514,15 +1514,36 @@ JWT_EXPORT
int jwks_item_free(jwk_set_t *jwk_set, size_t index);
/**
* Free all memory associated with all @ref jwk_item_t in a @ref jwk_set_t.
* @brief Remove and free all jwk_item_t in a jwk_set_t
*
* The jwk_set_t becomes an empty set.
*
* @param jwk_set A JWKS object
* @param jwk_set Pointer to a JWKS object
* @return The number of items deleted
*/
JWT_EXPORT
int jwks_item_free_all(jwk_set_t *jwk_set);
/**
* @brief Free all keys marked with an error in a jwk_set_t
*
* The jwk_set_t becomes an empty set.
*
* @param jwk_set Pointer to a JWKS object
* @return The number of items with an error that were deleted
*/
JWT_EXPORT
int jwks_item_free_bad(jwk_set_t *jwk_set);
/**
* @brief Return the number of keys in a jwk_set_t
*
* @param jwk_set Pointer to a JWKS object
* @return The number of items in the set
*/
JWT_EXPORT
size_t jwks_item_count(const jwk_set_t *jwk_set);
/**
* @}
* @noop jwks_item_grp

View file

@ -207,6 +207,19 @@ const jwk_item_t *jwks_item_get(const jwk_set_t *jwk_set, size_t index)
return NULL;
}
int jwks_error_any(const jwk_set_t *jwk_set)
{
jwk_item_t *item = NULL;
int count = jwk_set->error;
list_for_each_entry(item, &jwk_set->head, node) {
if (item->error)
count++;
}
return count;
}
int jwks_item_is_private(const jwk_item_t *item)
{
return item->is_private_key ? 1 : 0;
@ -297,6 +310,22 @@ static int jwks_item_add(jwk_set_t *jwk_set, jwk_item_t *item)
return 0;
}
static void __item_free(jwk_item_t *todel)
{
if (todel->provider == JWT_CRYPTO_OPS_ANY)
jwt_freemem(todel->oct.key);
else
jwt_ops->process_item_free(todel);
/* A few non-crypto specific things. */
jwt_freemem(todel->kid);
json_decrefp(&todel->json);
list_del(&todel->node);
/* Free the container and the item itself. */
jwt_freemem(todel);
}
int jwks_item_free(jwk_set_t *jwk_set, const size_t index)
{
jwk_item_t *item = NULL, *todel = NULL;
@ -316,22 +345,37 @@ int jwks_item_free(jwk_set_t *jwk_set, const size_t index)
if (todel == NULL)
return 0;
if (todel->provider == JWT_CRYPTO_OPS_ANY)
jwt_freemem(todel->oct.key);
else
jwt_ops->process_item_free(todel);
/* A few non-crypto specific things. */
jwt_freemem(todel->kid);
json_decrefp(&todel->json);
list_del(&todel->node);
/* Free the container and the item itself. */
jwt_freemem(todel);
__item_free(todel);
return 1;
}
size_t jwks_item_count(const jwk_set_t *jwk_set)
{
size_t count = 0;
jwk_item_t *item = NULL;
list_for_each_entry(item, &jwk_set->head, node)
count++;
return count;
}
int jwks_item_free_bad(jwk_set_t *jwk_set)
{
jwk_item_t *item, *pos;
int count = 0;
list_for_each_entry_safe(item, pos, &jwk_set->head, node) {
if (!item->error)
continue;
__item_free(item);
count++;
}
return count;
}
int jwks_item_free_all(jwk_set_t *jwk_set)
{
int i;

View file

@ -53,10 +53,21 @@ START_TEST(test_jwks_keyring_load)
}
ck_assert_int_eq(fails, 0);
ck_assert_int_eq(i, 27);
i = jwks_item_count(g_jwk_set);
ck_assert_int_eq(i, 27);
ck_assert(jwks_item_free(g_jwk_set, 3));
i = jwks_item_count(g_jwk_set);
ck_assert_int_eq(i, 26);
i = jwks_item_free_bad(g_jwk_set);
ck_assert_int_eq(i, 0);
i = jwks_item_count(g_jwk_set);
ck_assert_int_eq(i, 26);
free_key();
}
END_TEST
@ -72,6 +83,9 @@ START_TEST(test_jwks_keyring_all_bad)
jwk_set = jwks_create_fromfile(KEYDIR "/bad_keys.json");
ck_assert_ptr_nonnull(jwk_set);
i = jwks_error_any(jwk_set);
ck_assert_int_eq(i, 14);
for (i = 0; (item = jwks_item_get(jwk_set, i)); i++) {
if (!jwks_item_error(item)) {
fprintf(stderr, "KID: %s\n",
@ -81,6 +95,12 @@ START_TEST(test_jwks_keyring_all_bad)
}
ck_assert_int_eq(i, 14);
i = jwks_item_free_bad(jwk_set);
ck_assert_int_eq(i, 14);
i = jwks_item_count(jwk_set);
ck_assert_int_eq(i, 0);
}
END_TEST