[PATCH v3 1/7] lib: uuid: add UUID v5 support

Heinrich Schuchardt xypron.glpk at gmx.de
Wed Jun 5 07:33:29 CEST 2024


On 5/31/24 15:50, Caleb Connolly wrote:
> Add support for generating version 5 UUIDs, these are determistic and work
> by hashing a "namespace" UUID together with some unique data. One intended
> usecase is to allow for dynamically generate payload UUIDs for UEFI
> capsule updates, so that supported boards can have their own UUIDs
> without needing to hardcode them.
>
> Tests for this are added in an upcoming patch.
>
> Signed-off-by: Caleb Connolly <caleb.connolly at linaro.org>
> ---
>   include/uuid.h | 17 +++++++++++++++++
>   lib/Kconfig    |  8 ++++++++
>   lib/uuid.c     | 37 +++++++++++++++++++++++++++++++++++++
>   3 files changed, 62 insertions(+)
>
> diff --git a/include/uuid.h b/include/uuid.h
> index f5a941250f48..539affaa47b9 100644
> --- a/include/uuid.h
> +++ b/include/uuid.h
> @@ -10,8 +10,9 @@
>   #ifndef __UUID_H__
>   #define __UUID_H__
>
>   #include <linux/bitops.h>
> +#include <linux/kconfig.h>
>
>   /*
>    * UUID - Universally Unique IDentifier - 128 bits unique number.
>    *        There are 5 versions and one variant of UUID defined by RFC4122
> @@ -142,8 +143,24 @@ void gen_rand_uuid(unsigned char *uuid_bin);
>    * @param          - uuid output type: UUID - 0, GUID - 1
>    */
>   void gen_rand_uuid_str(char *uuid_str, int str_format);
>
> +#if IS_ENABLED(CONFIG_UUID_GEN_V5)
> +/**
> + * gen_uuid_v5() - generate UUID v5 from namespace and other seed data.
> + *
> + * @namespace:   pointer to UUID namespace salt
> + * @uuid:        pointer to allocated UUID output
> + * @...:         NULL terminated list of seed data as pairs of pointers
> + *               to data and their lengths

It is unclear what this might mean.

According to your description ... could be

struct {
	void *data;
	u32 *length;
} ...[] = {
	{ &data_1, &length_1 },
	{ &data_2, &length_2 },
	{ NULL, NULL }
}

Do we have pointer to lengths?
Which data type do lengths have?

Please, provide an unambiguous description.

An example would help.

> + */
> +void gen_uuid_v5(const struct uuid *namespace, struct uuid *uuid, ...);
> +#else
> +static inline void gen_uuid_v5(const struct uuid *namespace, struct uuid *uuid, ...)
> +{
> +}
> +#endif
> +
>   /**
>    * uuid_str_to_le_bin() - Convert string UUID to little endian binary data.
>    * @uuid_str:	pointer to UUID string
>    * @uuid_bin:	pointer to allocated array for little endian output [16B]
> diff --git a/lib/Kconfig b/lib/Kconfig
> index 189e6eb31aa1..2941532f25cf 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -80,8 +80,16 @@ config RANDOM_UUID
>   	help
>   	  Enable the generation of partitions with random UUIDs if none
>   	  are provided.
>
> +config UUID_GEN_V5
> +	bool "Enable UUID version 5 generation"
> +	select LIB_UUID
> +	depends on SHA1

'select SHA1' might make things easier.

> +	help
> +	  Enable the generation of version 5 UUIDs, these are determistic and

%s/determistic/deterministic/

> +	  generated from a namespace UUID, and a string (such as a board name).
> +
>   config SPL_LIB_UUID
>   	depends on SPL
>   	bool
>
> diff --git a/lib/uuid.c b/lib/uuid.c
> index dfa2320ba267..2df0523e717f 100644
> --- a/lib/uuid.c
> +++ b/lib/uuid.c
> @@ -21,8 +21,9 @@
>   #include <part_efi.h>
>   #include <malloc.h>
>   #include <dm/uclass.h>
>   #include <rng.h>
> +#include <u-boot/sha1.h>
>
>   int uuid_str_valid(const char *uuid)
>   {
>   	int i, valid;
> @@ -368,8 +369,44 @@ void uuid_bin_to_str(const unsigned char *uuid_bin, char *uuid_str,
>   		}
>   	}
>   }
>
> +#if IS_ENABLED(CONFIG_UUID_GEN_V5)
> +void gen_uuid_v5(const struct uuid *namespace, struct uuid *uuid, ...)
> +{
> +	sha1_context ctx;
> +	va_list args;
> +	const uint8_t *data;
> +	uint8_t hash[SHA1_SUM_LEN];
> +	uint32_t tmp;
> +
> +	sha1_starts(&ctx);
> +	/* Hash the namespace UUID as salt */
> +	sha1_update(&ctx, (unsigned char *)namespace, UUID_BIN_LEN);
> +	va_start(args, uuid);
> +
> +	while ((data = va_arg(args, const uint8_t *))) {
> +		unsigned int len = va_arg(args, size_t);
> +
> +		sha1_update(&ctx, data, len);
> +	}
> +
> +	va_end(args);
> +	sha1_finish(&ctx, hash);
> +
> +	/* Truncate the hash into output UUID, it is already big endian */
> +	memcpy(uuid, hash, sizeof(*uuid));
> +
> +	/* Configure variant/version bits */
> +	tmp = be32_to_cpu(uuid->time_hi_and_version);
> +	tmp = (tmp & ~UUID_VERSION_MASK) | (5 << UUID_VERSION_SHIFT);

Currently we have

#define UUID_VERSION            0x4

Shouldn't we create

#define UUID_VARIANT_4 0x4 - to be used in gen_rand_uuid()
#define UUID_VARIANT_5 0x5 - to be used in gen_uuid_v5()

instead?

Please, provide a unit test for gen_uuid_v5() that passes multiple
strings to gen_uuid_v5() and checks the hash.

Best regards

Heinrich

> +	uuid->time_hi_and_version = cpu_to_be32(tmp);
> +
> +	uuid->clock_seq_hi_and_reserved &= UUID_VARIANT_MASK;
> +	uuid->clock_seq_hi_and_reserved |= UUID_VARIANT << UUID_VARIANT_SHIFT;
> +}
> +#endif
> +
>   #if defined(CONFIG_RANDOM_UUID) || defined(CONFIG_CMD_UUID)
>   void gen_rand_uuid(unsigned char *uuid_bin)
>   {
>   	u32 ptr[4];
>



More information about the U-Boot mailing list