In uuid.h the function uuid_generate_v5 had a 'namespace' parameter which is a reserved C++ keywork. Renamed to 'ns'. Signed-off-by: Daniel Nicoletti <dantti12@gmail.com>
268 lines
6.3 KiB
C
268 lines
6.3 KiB
C
/*
|
|
* Copyright (c) 2025, SECO Mind Srl
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/sys/uuid.h>
|
|
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#if defined(CONFIG_UUID_V4)
|
|
#include <zephyr/random/random.h>
|
|
#endif
|
|
|
|
#if defined(CONFIG_UUID_V5)
|
|
#include <mbedtls/md.h>
|
|
#endif
|
|
|
|
#if defined(CONFIG_UUID_BASE64)
|
|
#include <zephyr/sys/base64.h>
|
|
#endif
|
|
|
|
#define UUID_STR_POSITION_FIRST_HYPHEN (8U)
|
|
#define UUID_STR_POSITION_SECOND_HYPHEN (13U)
|
|
#define UUID_STR_POSITION_THIRD_HYPHEN (18U)
|
|
#define UUID_STR_POSITION_FOURTH_HYPHEN (23U)
|
|
|
|
#define UUID_POSITION_VERSION (6U)
|
|
#define UUID_OFFSET_VERSION (4U)
|
|
#define UUID_MASK_VERSION (0xF0U)
|
|
#define UUID_POSITION_VARIANT (8U)
|
|
#define UUID_OFFSET_VARIANT (6U)
|
|
#define UUID_MASK_VARIANT (0xC0)
|
|
|
|
#define UUID_V4_VERSION (4U)
|
|
#define UUID_V4_VARIANT (2U)
|
|
#define UUID_V5_VERSION (5U)
|
|
#define UUID_V5_VARIANT (2U)
|
|
|
|
#if defined(CONFIG_UUID_V4) || defined(CONFIG_UUID_V5)
|
|
static void overwrite_uuid_version_and_variant(uint8_t version, uint8_t variant, struct uuid *out)
|
|
{
|
|
/* Clear the 'ver' and 'var' fields */
|
|
out->val[UUID_POSITION_VERSION] &= ~UUID_MASK_VERSION;
|
|
out->val[UUID_POSITION_VARIANT] &= ~UUID_MASK_VARIANT;
|
|
/* Update the 'ver' and 'var' fields */
|
|
out->val[UUID_POSITION_VERSION] |= (uint8_t)(version << UUID_OFFSET_VERSION);
|
|
out->val[UUID_POSITION_VARIANT] |= (uint8_t)(variant << UUID_OFFSET_VARIANT);
|
|
}
|
|
#endif
|
|
|
|
static bool should_be_hyphen(unsigned int position)
|
|
{
|
|
switch (position) {
|
|
case UUID_STR_POSITION_FIRST_HYPHEN:
|
|
case UUID_STR_POSITION_SECOND_HYPHEN:
|
|
case UUID_STR_POSITION_THIRD_HYPHEN:
|
|
case UUID_STR_POSITION_FOURTH_HYPHEN:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
#if defined(CONFIG_UUID_V4)
|
|
int uuid_generate_v4(struct uuid *out)
|
|
{
|
|
if (out == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
/* Fill the whole UUID struct with a random number */
|
|
sys_rand_get(out->val, UUID_SIZE);
|
|
/* Update version and variant */
|
|
overwrite_uuid_version_and_variant(UUID_V4_VERSION, UUID_V4_VARIANT, out);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_UUID_V5)
|
|
int uuid_generate_v5(const struct uuid *ns, const void *data, size_t data_size,
|
|
struct uuid *out)
|
|
{
|
|
if (out == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
int ret = 0;
|
|
int mbedtls_err = 0;
|
|
mbedtls_md_context_t ctx = {0};
|
|
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
|
|
const size_t sha_1_bytes = 20;
|
|
uint8_t sha_result[sha_1_bytes];
|
|
|
|
mbedtls_md_init(&ctx);
|
|
mbedtls_err = mbedtls_md_setup(&ctx, md_info, 0);
|
|
/* Might return: MBEDTLS_ERR_MD_BAD_INPUT_DATA or MBEDTLS_ERR_MD_ALLOC_FAILED */
|
|
switch (mbedtls_err) {
|
|
case 0:
|
|
break;
|
|
case MBEDTLS_ERR_MD_BAD_INPUT_DATA:
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
case MBEDTLS_ERR_MD_ALLOC_FAILED:
|
|
ret = -ENOMEM;
|
|
goto exit;
|
|
default:
|
|
ret = -ENOTSUP;
|
|
goto exit;
|
|
}
|
|
mbedtls_err = mbedtls_md_starts(&ctx);
|
|
if (mbedtls_err != 0) {
|
|
/* Might return MBEDTLS_ERR_MD_BAD_INPUT_DATA */
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
mbedtls_err = mbedtls_md_update(&ctx, ns->val, UUID_SIZE);
|
|
if (mbedtls_err != 0) {
|
|
/* Might return MBEDTLS_ERR_MD_BAD_INPUT_DATA */
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
mbedtls_err = mbedtls_md_update(&ctx, data, data_size);
|
|
if (mbedtls_err != 0) {
|
|
/* Might return MBEDTLS_ERR_MD_BAD_INPUT_DATA */
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
mbedtls_err = mbedtls_md_finish(&ctx, sha_result);
|
|
if (mbedtls_err != 0) {
|
|
/* Might return MBEDTLS_ERR_MD_BAD_INPUT_DATA */
|
|
ret = -EINVAL;
|
|
goto exit;
|
|
}
|
|
|
|
/* Store the computed SHA1 in the out struct */
|
|
for (unsigned int i = 0; i < UUID_SIZE; i++) {
|
|
out->val[i] = sha_result[i];
|
|
}
|
|
/* Update version and variant */
|
|
overwrite_uuid_version_and_variant(UUID_V5_VERSION, UUID_V5_VARIANT, out);
|
|
|
|
exit:
|
|
mbedtls_md_free(&ctx);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
int uuid_copy(const struct uuid *data, struct uuid *out)
|
|
{
|
|
if (out == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
memcpy(out->val, data->val, UUID_SIZE);
|
|
return 0;
|
|
}
|
|
|
|
int uuid_from_buffer(const uint8_t data[UUID_SIZE], struct uuid *out)
|
|
{
|
|
if ((data == NULL) || (out == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
memcpy(out->val, data, UUID_SIZE);
|
|
return 0;
|
|
}
|
|
|
|
int uuid_from_string(const char data[UUID_STR_LEN], struct uuid *out)
|
|
{
|
|
if ((data == NULL) || (strlen(data) + 1 != UUID_STR_LEN) || (out == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
for (unsigned int i = 0; i < UUID_STR_LEN - 1; i++) {
|
|
char char_i = data[i];
|
|
/* Check that hyphens are in the right place */
|
|
if (should_be_hyphen(i)) {
|
|
if (char_i != '-') {
|
|
return -EINVAL;
|
|
}
|
|
continue;
|
|
}
|
|
/* Check if the given input is hexadecimal */
|
|
if (!isxdigit(char_i)) {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
/* Content parsing */
|
|
unsigned int data_idx = 0U;
|
|
unsigned int out_idx = 0U;
|
|
|
|
while (data_idx < UUID_STR_LEN - 1) {
|
|
if (should_be_hyphen(data_idx)) {
|
|
data_idx += 1;
|
|
continue;
|
|
}
|
|
|
|
size_t hex2bin_rc =
|
|
hex2bin(&data[data_idx], 2, &out->val[out_idx], UUID_SIZE - out_idx);
|
|
if (hex2bin_rc != 1) {
|
|
return -EINVAL;
|
|
}
|
|
out_idx++;
|
|
data_idx += 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int uuid_to_buffer(const struct uuid *data, uint8_t out[UUID_SIZE])
|
|
{
|
|
if (out == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
memcpy(out, data->val, UUID_SIZE);
|
|
return 0;
|
|
}
|
|
|
|
int uuid_to_string(const struct uuid *data, char out[UUID_STR_LEN])
|
|
{
|
|
if (out == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
snprintf(out, UUID_STR_LEN,
|
|
"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
data->val[0], data->val[1], data->val[2], data->val[3], data->val[4], data->val[5],
|
|
data->val[6], data->val[7], data->val[8], data->val[9], data->val[10],
|
|
data->val[11], data->val[12], data->val[13], data->val[14], data->val[15]);
|
|
return 0;
|
|
}
|
|
|
|
#if defined(CONFIG_UUID_BASE64)
|
|
int uuid_to_base64(const struct uuid *data, char out[UUID_BASE64_LEN])
|
|
{
|
|
if (out == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
size_t olen = 0;
|
|
|
|
base64_encode(out, UUID_BASE64_LEN, &olen, data->val, UUID_SIZE);
|
|
return 0;
|
|
}
|
|
|
|
int uuid_to_base64url(const struct uuid *data, char out[UUID_BASE64URL_LEN])
|
|
{
|
|
if (out == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Convert UUID to RFC 3548/4648 base 64 notation */
|
|
size_t olen = 0;
|
|
char uuid_base64[UUID_BASE64_LEN] = {0};
|
|
|
|
base64_encode(uuid_base64, UUID_BASE64_LEN, &olen, data->val, UUID_SIZE);
|
|
/* Convert UUID to RFC 4648 sec. 5 URL and filename safe base 64 notation */
|
|
for (unsigned int i = 0; i < UUID_BASE64URL_LEN - 1; i++) {
|
|
if (uuid_base64[i] == '+') {
|
|
uuid_base64[i] = '-';
|
|
}
|
|
if (uuid_base64[i] == '/') {
|
|
uuid_base64[i] = '_';
|
|
}
|
|
}
|
|
memcpy(out, uuid_base64, UUID_BASE64URL_LEN - 1);
|
|
out[UUID_BASE64URL_LEN - 1] = 0;
|
|
return 0;
|
|
}
|
|
#endif
|